- 1. malloc和new
- 1.1 初始化对象
- 1.2 申请对象
- 1.3 operator new
- 2. 对象成员方法的设计
- 2.1 const——常对象只能调动常方法
- 2.2 tmp对象能否改变?
- 2.3 全局对象能否设置成常方法?
- 2.4 成员方法能否以引用返回?
- 2. 实现整型栈
- 2.1 初始化顺序
- 2.2 实现整型栈代码
- 3. 拷贝构造函数
- 3.1 拷贝构造函数定义
- 3.2 拷贝构造函数类型
- 3.3 拷贝构造函数特点
- 3.4 将亡值
- 3.5 拷贝构造函数返回引用与返回非引用的区别?
- 3.5 1 非引用返回:Object fun(const Object& obj)
- 3.5 2 引用返回:Object& fun(const Object& obj)(错误返回)
- 3.5.2.1 什么时候可以引用返回?
- 3.6 为什么要在主函数中构建将亡值?
- 3.7 析构顺序和构造顺序
- 3.8 系统内存空间分配
- 4. 运算符重载
- 4.1 定义
- 4.2 代码示例
- 4.3 常用的运算符重载函数
- 4.4 如何防止函数自赋值?
- 5. 数组名
- 6. 缺省函数
- 6.1 运算符重载函数特点
- 6.2 前置++与后置++
- 6.2.1 前置“++”格式
- 6.2.2 后置“++”格式
- 6.2.3 前置++为单目,后置++为双目
- 6.3 C++中不允许重载的运算符(极少数)
- 6.4 重载运算符的限制
初始化一个对象
int main()
{
//new创建单个对象
Complex* cp = new Complex(1, 2);
cp->Print();
delete cp;//释放一个对象
}
初始化一组对象
int main()
{
//创建一组对象
int n = 2;
//cin >> n;
Complex* cp = new Complex[n]{ {1,2},{2,3} };
delete[] cp;//释放一组对象
return 0;
}
1.2 申请对象
只有new关键字在申请空间时候才会申请4字节空间存放对象个数。
只是进行空间开辟,而不进行对象构建。
int main()
{
int n = 10;
Complex* cp = (Complex*)::operator new(sizeof(Complex) * n, nothrow);//不能抛出异常
for (int i = 0; i < n; ++i)
{
new(&cp[i])Complex(i, i);//定位new,开辟空间完成后用定位new创建对象
}
return 0;
}
2. 对象成员方法的设计
2.1 const——常对象只能调动常方法
2.2 tmp对象能否改变?
2.3 全局对象能否设置成常方法?
不可以,因为全局对象是没有this指针。
2.4 成员方法能否以引用返回?如果不受影响,就可以用引用返回。
#include#include using namespace std; //实现整型栈 class MyStack { enum { STACK_INIT_SIZE = 10, STACK_INC_SIZE = 2 }; int* _data; int _size; int _top; public: MyStack() :_data{ nullptr }, _size(STACK_INIT_SIZE), _top(-1) { _data = new int[_size]; } ~MyStack() { delete[] _data; _data = nullptr; _size = 0; _top = -1; } bool Resize(int size)//增容到size大小 { if (size < Capacity()) return false; int* newdata = new(nothrow) int[size]; if (newdata == nullptr) { return false; } memmove(newdata, _data, sizeof(int) * Size()); delete[] _data; _data = newdata; _size = size; return true; } int Capacity() const//栈长度 { return _size; } int Size() const//元素个数 { return _top + 1; } bool Full() const//判满 { return Size() == _size; } bool Empty()//判空 { return Size() == 0; } bool Push(int val)//入栈 { if (Full() && Resize(Capacity() * STACK_INC_SIZE)) { return false; } _top += 1; _data[_top] = val; return true; } int Top() const//取栈顶元素,元素不出栈 { return _data[_top]; } bool Pop()//只是出栈 { if (Empty()) { return false; } _top -= 1; return true; } bool GetPop()//取栈顶元素和出栈 { return _data[_top--]; } }; int main() { MyStack mys; mys.Resize(20000);//直接申请一块大内存,后面不用在进行增容,系统运行效率提高 for (int i = 0; i < 100; ++i) { cout << mys.Capacity() << " " << mys.Size() << endl; mys.Push(i); } while (!mys.Empty()) { cout << mys.Top() << endl; mys.Pop(); } }
运行结果
同一个类的对象在内存中有完全相同的结构,如果作为一个整体进行复制或称拷贝是完全可行的。这个拷贝过程只需要拷贝数据成员,而函数成员是共用的(只有一份拷贝)。在建立对象时可用同一类的另一个对象来初始化该对象的存储空间,这时所用的构造函数称为拷贝构造函数(Copy Constructor)。
3.2 拷贝构造函数类型- ① 系统自动补充缺省构造函数
- ② 系统自动补充缺省析构函数
- ③ 系统自动补充拷贝构造函数
- 函数名和类型名相同,参数为类型的引用。
- 调用构造函数创建对象,当用对象创建另一个对象,调用拷贝构造函数。
- 析构几次就代表创建了几个对象。
Object(const Object& obj)//加引用可以防止死递归,加const不允许对象进行修改
:value(obj.value)
{
cout << "Copy Create" << endl;
}
3.4 将亡值
当函数返回时候构建对象副本时产生的临时数值,将亡值对象是一个常性对象
Object fun(const Object& obj)//3 用引用返回和不用引用返回区别:
{
int val = obj.Value();
Object obja(val);// 4
return obja;// 调用拷贝构造函数构建将亡值 5
}
int main()
{
Object objx(0);// 1
Object objy(0);// 2
objy = fun(objx);
cout << objy.Value() << endl;
return 0;
}
3.5 1 非引用返回:Object fun(const Object& obj)
进入主函数分配栈帧,为对象创建空间,调用构造函数创建对象,将将亡值对象的地址送入eax,将eax所指向的对象赋值给主函数变量(间接寻址)
3.5 2 引用返回:Object& fun(const Object& obj)(错误返回)引用返回不用建立将亡值对象,只需要把地址存放给eax,eax存放变量地址
静态关键字只能修饰函数名,不能修饰其他
3.5.2.1 什么时候可以引用返回?当对象的生存期不受函数影响时可以引用返回
Object& operator=(const Object& obj)
{
this->value;
return *this;
}
3.6 为什么要在主函数中构建将亡值?
主函数调用fun函数,所以将亡值构建在主函数的内存空间中。
3.7 析构顺序和构造顺序代码示例
#includeusing namespace std; class Object { int value; public: Object() { cout << "Object::Object" << this << endl; }//缺省构造函数 Object(int x) :value(x) { cout << "Object::Object" << this << endl; }//带参构造函数 ~Object(){ cout << "Object::~Object" << this << endl; }//系统补充析构函数 void SetValue(int x) const { x = value; } int GetValue()const { return value; } Object(Object& obj) :value(obj.value) { cout << "Copy Create:" << this << endl; } }; Object fun(Object obj)//3 如果要用形参改变实参,则不加const,如果不改变,则加const { int val = obj.GetValue(); Object obja(val);// 4 return obja;// 调用拷贝构造函数构建将亡值 5 } int main() { Object objx(0);// 1 Object objy(0);// 2 objy = fun(objx); return 0; }
运行结果
函数名为合法标识符,操作符不能作为一个函数有效的函数名
4.2 代码示例class Object
{
public:
Object() {}//构造函数
~Object() {}//析构函数
Object(const Object& x) {}//拷贝构造函数
Object& operator=(const Object& x)//赋值重载语句
{
if(this!=&obj)//防止相同类型进行赋值
{
this->value;
}
return *this;
}
Object* operator&()//普通对象取地址符重载
{
return this;
}
const Object* operator&()const//常对象取地址符重载
{
return this;
}
Object(Object&& x) {}//移动构造函数
Object& operator=(const Object&& x) {}//移动赋值函数
};
4.3 常用的运算符重载函数
| 常用函数 | |
|---|---|
| 1 | 构造函数 |
| 2 | 拷贝构造函数 |
| 3 | 析构函数 |
| 4 | 赋值重载语句 |
| 5 | 普通对象取地址符重载 |
| 6 | 常对象取地址符重载 |
| 7 | 移动构造函数 |
| 8 | 移动赋值函数 |
c3 = c1 + c2;
//c3 = c1.operator+(c2);
//c3 = operator+(&c1, c2);
4.4 如何防止函数自赋值?
Object& operator=(const Object& obj)
{
if (this != &obj)
{
this->value = obj.value;
}
return *this;
}
5. 数组名
【类型(类型推演)和大小(替换)】
int main()
{
int ar[10] = { 12,23,34,45,56,67,78,89,90,100 };
sizeof(ar);//代表整个数组
int(*p)[10] = &ar;//整个数组地址
int(&br)[10] = ar;//引用数组
}
6. 缺省函数
6.1 运算符重载函数特点
- (1)运算符重载函数的函数名必须为关键字operator加一个合法的运算符。在调用该函数时,将右操作数作为函数的实参。
- (2)当用类的成员函数实现运算符的重载时,运算符重载函数的参数(当为双目运算符时)为一个或(当为单目运算符时)没有。运算符的左操作数一定是对象,因为重载的运算符是该对象的成员函数,而右操作数是该函数的参数。
- (3)单目运算符“++”和“–”存在前置与后置问题。
返回类型 类名::operator++(){……}
6.2.2 后置“++”格式
返回类型 类名::operator++(int){……}
后置“++”中的参数 int 仅用作区分,并无实际意义,可以给一个变量名,也可以不给变量名。
6.2.3 前置++为单目,后置++为双目代码示例
Int& operator++()
{
value += 1;
return *this;
}
Int operator++(int)
{
Int tmp = *this;
++* this;
return tmp;
}
代码示例
Int& operator+(const Int& it) const//对象和对象相加
{
return Int(this->value + it, value);
}
Int& operator+(const int x) const//对象和整型变量相加
{
return Int(this->value + x);
}
Int operator+(const int x, const Int& it)//整型变量和对象相加
{
return it + x;
}
bool operator==(const Int& it) const//判断两个对象的值是否相等
{
return this->value == it.value;
}
bool operator! = (const Int & it) const//判断两个对象的值是否不相等
{
return !(*this == it);
}
bool operator<(const Int& it) const//小于
{
return this->value < it.value;
}
bool operator>=(const int& it) const//大于等于
{
return!(this < it);
}
bool operator>(const int& it) const//大于
{
return this->value > it.value;
}
bool operator<=(const int& it) const//小于等于
{
return!(this > it);
}
重载自加和加号运算符时,以函数方式进行
6.3 C++中不允许重载的运算符(极少数) 6.4 重载运算符的限制- 不可臆造新的运算符
- 不能改变运算符原有的优先级、结合性和语法结构,不能改变运算符操作数的个数
- 运算符重载不宜使用过多
- 重载运算符含义必须清楚,不能有二义性



