赋值运算符函数
大约 3 分钟
赋值运算符函数

形式
赋值运算是一种很常见的运算,比如:
int x = 1, y = 2;
x = y;
同样地, 我们也希望该操作能作用于自定义类类型,比如:
Point pt1(1, 2), pt2(3, 4);
pt1 = pt2;//赋值操作
在执行pt1 = pt2;该语句时,pt1与pt2都存在,所以不存在对象的构造,这要与 Point pt2 = pt1;语句区分开,这是不同的。
Point pt1(1, 2);
/* Point pt4 = pt1;//拷贝构造函数 */
Point pt4(pt1);//拷贝构造函数
Point pt2(3, 4);
pt2 = pt1;//赋值运算符函数
在这里,当=
作用于对象时,其实是把它当成一个函数来看待的。在执行pt1 = pt2;该语句时,需要调用的是赋值运算符函数。其形式如下:
返回类型 类名::operator=(参数列表)
{
//...
}
如果类中没有显式定义赋值运算符函数时,编译器会自动提供一个缺省的赋值运算符函数。
Point &Point::operator=(const Point &rhs)
{
_ix = rhs._ix;
_iy = rhs._iy;
return *this;
}
深拷贝和浅拷贝问题
class Computer
{
public:
Computer(const char *brand, double price)
: _brand(new char[strlen(brand) + 1]())
, _price(price)
{
cout << "Computer(const char *, double)" << endl;
}
Computer &operator=(const Computer &rhs)
{
_brand = rhs._brand; //浅拷贝
_price = rhs._price;
return *this;
}
Computer &Computer::operator=(const Computer &rhs)
{
if(this != &rhs) //1、自复制
{
delete [] _brand; //2、释放左操作数
_brand = nullptr;
_brand = new char[strlen(rhs._brand) + 1](); //3、深拷贝
strcpy(_brand, rhs._brand);
_price = rhs._price;
}
return *this; //4、返回*this
}
private:
char *_brand; //指向堆内存的指针
double _price;
};
//执行构造初始化
Computer pc1("Huawei Matebook14", 5699);
Computer pc2 = pc1;
Q:引用符号可以去掉吗?
如果去掉,会多执行一次拷贝构造函数,效率就会降低
Q:const可以去掉吗:
如果右操作数是右值的时候,就会产生非const左值引用不能绑定到右值的报错
Q:赋值运算符函数的返回类型可以是void?
考虑连等情况
空类
#include <iostream>
using std::cout;
using std::endl;
class Empty
{
//无参构造函数
//拷贝构造函数
//赋值运算符函数
//析构函数
};
int main(int argc, char **argv)
{
cout << "sizeof(Empty) = " << sizeof(Empty) << endl;
Empty e1;
Empty e2;
Empty e3;
printf("&e1 = %p\n", &e1);
printf("&e2 = %p\n", &e2);
printf("&e3 = %p\n", &e3);
return 0;
}
$./a.out
sizeof(Empty) = 1
&e1 = 0x7ffe6ef931ef
&e2 = 0x7ffe6ef931ee
&e3 = 0x7ffe6ef931ed
一个空的类,编译器会自动提供哪些函数
- 无参构造函数
- 拷贝构造函数
- 赋值运算符函数
- 析构函数
空类的大小不为0
C++标准指出,不允许一个对象(当然包括类对象)的大小为0,。这是由于:
- new需要分配不同的内存地址,不能分配内存大小为0的空间
- 避免除以 sizeof(T)时得到除以0错误
故使用****来区分空类。
值得注意的是,这并不代表一个空的基类也需要加一个字节到子类中去。这种情况下,空类并不是独立的,它附属于子类。子类继承空类后,子类如果有自己的数据成员,而空基类的一个字节并不会加到子类中去。例如,
class Empty {};
struct D : public Empty {int a;}; //sizeof(D)为4
再来看另一种情况,一个类包含一个空类对象数据成员。
class Empty {};
class HoldsAnInt {
int x;
Empty e;
};
在大多数编译器中,你会发现 sizeof(HoldsAnInt)
输出为8。这是由于,Empty类的大小虽然为1,然而为了内存对齐,编译器会为HoldsAnInt额外加上一些字节,使得HoldsAnInt被放大到足够又可以存放一个int。