类的构造函数、析构函数与赋值函数
1、每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其他的称为普通构造函数)。对于任意一个类A,如果不想编写上述函数,C++编译器将自动为A产生四个缺省函数
A(void); //缺省的无参数构造函数
A(const A &a); //缺省的拷贝构造函数 //浅拷贝
~A(void); //缺省的析构函数
A & operator =(const A& a); //缺省的赋值函数 //浅拷贝
2、不少难以察觉的程序错误是由于变量没有被正确初始化或清除造成的。
3、如果类存在继承关系,派生类必须在其初始化表里调用基类的构造函数。类的const常量只能在初始化表里被初始化。
4、类的数据成员可以采用初始化表或函数体内赋值两种方式,这两种方式的效率不完全相同。非内部数据类型的成员对象应当采用第一种方式初始化,以获取更高的效率。
例如:
B:B(const A &a)
: m_a(a)
{
...
}//调用了A的拷贝构造函数
B:B(const A &a)
{
m_a = a;
}//暗地里先调用了A的无参数构造函数,在调用A的赋值函数。
5、构造和析构的次序:构造从类的最根部开始,先调用基类的构造函数,然后调用成员对象的构造函数。析构则与构造完全相反的次序执行,该次序是唯一的,否则编译器将无法自动执行析构过程。成员对象的初始化次序只由声明的次序决定。
6、区分拷贝构造函数和赋值函数
String a("hello");
String b("world");
String c = a; //拷贝构造函数,最好写成c(a); 在对象被创建时调用
a = b; //赋值构造函数, 对象已经存在时调用
7、“引用”不可能是NULL,而指针可能是NULL;
8、拷贝构造函数一般分四步实现
String & String::operator =(const String &other)
{
if (this == &other) //(1)检查自赋性,不要写成*this == other
{
return *this;
}
delete m_data; //(2)释放原有内存
int length = strlen(other.m_data);
m_data = new char[length + 1]; //(3)分配新的内存,并复制内容
strcpy(m_data, other.m_data);
return *this; //(4)返回本对象的引用,不要写成return &other,返回栈上的引用
}
9、基类的构造函数、析构函数、赋值函数都不能被派生类继承,如果类之间存在继承,应注意以下事项
(1)派生类的构造函数应在其初始化表里调用基类的构造函数。
(2)基类与派生类的析构函数应该为虚(即加virual关键字)
(3)在编写派生类的赋值函数时,不要忘记对基类的数据成员重新赋值。
Derived & Derived::operator =(const Derived &other)
{
if (this == &other)
return *this;
Base::operator =(other);//对基类重新赋值,因为不能直接操作私有数据成员
m_x = other.mx;
return *this;
}
10、构造函数、析构函数、赋值函数是类的”Big-Three”。是任何类的最重要函数,不容忽视。