1.赋值运算符重载格式
参数类型:const &,传递引用可以提高传参效率。
返回值类型:&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值检测是否自己给自己赋值。
返回*this :要复合连续赋值的含义。
注意区分左右。
#include <iostream> using namespace std; class N1 { public: N1(int x, int y) { _a = x; _b = y; } //赋值运算 N1& operator=(const N1& s)//这里也可以不用引用,但是效率会降低,因为传值传的是构造体的拷贝 { _a = s._a; _b = s._b; return *this;//返回值是s1,一般返回的都是左值 } void print() { cout << _a << ' ' << _b << endl; } private: int _a; int _b; }; int main() { N1 s1(1, 2); N1 s2(3, 4); N1 s3(5, 6); s3 =s1 = s2; s3.print(); return 0; }
2.自定义类型的赋值
因为和拷贝极其相似,那么这里也一定会有默认浅拷贝的的问题。
#include <iostream> using namespace std; class stack { public: stack(int capacity = 4) { _a = (int*)malloc(capacity * sizeof(int)); if (_a == nullptr) { perror("malloc开辟失败"); exit(-1); } _top = 0; _capacity = capacity; } ~stack() { free(_a); _a = nullptr; _top = 0; _capacity = 0; } void Push(int x) { _a[_top] = x; _top++; } private: int* _a; int _top; int _capacity; }; int main() { stack s1; s1.Push(1); s1.Push(2); stack s2; s2.Push(3); s2.Push(4); s1 = s2; return 0; }
同样,这里还是深浅拷贝的问题。
这里析构一个位置了两次,所以我们要自己写一个。
注意:这和拷贝不一样,一个是将创建完毕的对象的值拷贝到正在创建中对象的里面,不用考虑两块空间大小是否相同,但是赋值不同,如果一个对象空间过大,另一个对象就会产生越界访问的问题。
那么这个问题应该如何解决呢?
如果去realloc,那么两块空间差距太大的话,就会产生很多的内存碎片。
其实核心思路是赋值,那么s1._a中的内容包括空间本身都是可以舍弃的,所以我们可以直接释放掉原来的空间,然后按照赋值空间的大小重新开辟一个在进行赋值。
#include <iostream> using namespace std; class stack { public: stack(int capacity = 4) { _a = (int*)malloc(capacity * sizeof(int)); if (_a == nullptr) { perror("malloc开辟失败"); exit(-1); } _top = 0; _capacity = capacity; } ~stack() { cout << "析构" << endl; free(_a); _a = nullptr; _top = 0; _capacity = 0; } void Push(int x) { _a[_top] = x; _top++; } stack& operator=(stack& s) { free(_a); _a = (int*)malloc(s._capacity * sizeof(int)); if(_a==nullptr) { perror("malloc重新开辟失败"); exit(-1); } _top = s._top; _capacity = s._capacity; memcpy(_a, s._a, s._top * sizeof(int)); return *this; } private: int* _a; int _top; int _capacity; }; int main() { stack s1; s1.Push(1); s1.Push(2); stack s2; s2.Push(3); s2.Push(4); s1 = s2; return 0; }
那么,如果是自己给自己赋值是会有问题的,因为进入函数之后自己就把自己给释放掉了。
虽然不会报错,但是容易导致数据丢失,因为你释放掉这块空间,这块空间里面的数据就不一定得到保证,并且自己赋值自己没有必要进行任何操作,所以我们在进行释放等等操作之前进行一个判断是最好的。
#include <iostream> using namespace std; class stack { public: stack(int capacity = 4) { _a = (int*)malloc(capacity * sizeof(int)); if (_a == nullptr) { perror("malloc开辟失败"); exit(-1); } _top = 0; _capacity = capacity; } ~stack() { cout << "析构" << endl; free(_a); _a = nullptr; _top = 0; _capacity = 0; } void Push(int x) { _a[_top] = x; _top++; } stack& operator=(stack& s) { cout << "赋值" <<endl; if (this != &s)//比较两个对象的地址是否相同,如果相同就是同一个对象 { free(_a); _a = (int*)malloc(s._capacity * sizeof(int)); if (_a == nullptr) { perror("malloc重新开辟失败"); exit(-1); } _top = s._top; _capacity = s._capacity; memcpy(_a, s._a, s._top * sizeof(int)); } return *this; } private: int* _a; int _top; int _capacity; }; int main() { stack s1; s1.Push(1); s1.Push(2); stack s2; s2.Push(3); s2.Push(4); s1 = s1; return 0; }
那么成员里面是自定义类型的对象进行赋值也是和拷贝一样的,是调用自定义类型里面的赋值。
前置后置++重载
按照operator特性,要把运算符放到后面,那么怎么区分前置++和后置++呢?
因为前置后置++只是+1而已,所以没必要带参数(当然没算this指针)。
#include <iostream> using namespace std; class N { public: N(int x) { _a = x; } N& operator++()//前置++ { ++_a; return *this; } N operator++(int)//后置++,返回值不能用引用,因为返回的是临时数据 { N s(*this); ++_a; return s;//因为是后置++,所以返回的应该是++之前的数据 } void print() { cout << _a << endl; } private: int _a; }; int main() { N s1(1); ++s1; s1.print();//打印的是前置++的值 N x(0);//用来接收临时值 N s2(1); x = s2++; x.print();//打印的是后置++返回的临时值 s2.print();//打印的是后置++完毕的值 return 0; }
C++规定,在参数中加一个int就是后置++,不加就是前置++。
前置++和后置++的返回值不一样,这里要注意,因为前置++是先++后使用,所以返回++完毕的值就可以了,后置++是先使用后++,所以就需要先用一个同类的临时对象来储存需要后置++的对象,然后再将需要后置++的对象进行++,然后返回临时对象,返回的时候不能用引用,因为出了函数临时对象就被销毁了。
const成员函数
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
#include <iostream> using namespace std; class N { public: N(int x) { _a = x; } void print() { cout << _a << endl; } private: int _a; }; int main() { const N s(1);//这里初始化的对象s有了const属性 s.print(); return 0; }
在const属性的对象当中调用成员函数,因为成员函数有隐藏的this指针,格式是 N* const this,意思是this指针指向的位置不能改变,而加了const 的对象s是const N* this,不允许修改this指针指向的内容。
这里就属于权限放大。
想解决问题可以变成这种格式
const N* const this
权限缩小是可以的。
这时候我们只需要在你调用的函数后面加上const就可以了。
#include <iostream> using namespace std; class N { public: N(int x) { _a = x; } void print()const//这里就等同于在this指针前面加了一个const { cout << _a << endl; } private: int _a; }; int main() { const N s(1); s.print(); return 0; }
取地址及const取地址操作符重载
这个几乎不用自己去写,其实就是取对象的地址,默认的也是一样的效果。
#include <iostream> using namespace std; class N { public: N(int x) { _a = x; } N* operator&()//普通 { return this; } const N* operator&()const//如果这里的返回值不加const就是权限放大 { return this; } private: int _a; }; int main() { N s1(1); const N s2(1); cout << &s1 << endl; cout << &s2 << endl; return 0; }











