基类的构造函数,析构函数,赋值操作符都不能被派生类继承。
派生类的构造函数
派生类的数据成员由所有基类的数据成员与派生类新增的数据成员共同组成,如果派生类新增成员中包括其他类的对象(子对象),派生类的数据成员中实际上还间接包括了这些对象的数据成员。因此,构造派生类的对象时,必须对基类数据成员、新增数据成员和成员对象的数据成员进行初始化。派生类的构造函数必须要以合适的初值作为参数,隐含调用基类和新增对象成员的构造函数,来初始化它们各自的数据成员,然后再加入新的语句对新增普通数据成员进行初始化。
派生类构造函数的一般格式如下:
<派生类名>::<派生类名>(<参数表>) : <基类名1>(<参数表1>),
……,
<基类名n>(<参数表n>),
<子对象名1>(<参数表n+1>),
……,
<子对象名m>(<参数表n+m>)
{
<派生类构造函数体> //派生类新增成员的初始化
}
说明:
(1) 对基类成员和子对象成员的初始化必须在成员初始化列表中进行,新增成员的初始化既可以在成员初始化列表中进行,也可以在构造函数体中进行。
(2) 派生类构造函数必须对这三类成员进行初始化,其执行顺序如下所述。
. 调用基类构造函数;
. 调用子对象的构造函数;
. 派生类的构造函数体;
(3) 当派生类有多个基类时,处于同一层次的各个基类的构造函数的调用顺序取决于定义派生类时声明的顺序(自左向右),而与在派生类构造函数的成员初始化列表中给出的顺序无关。
(4) 如果派生类的基类也是一个派生类,则每个派生类只需负责其直接基类的构造,依次上溯。
(5) 当派生类中有多个子对象时,各个子对象构造函数的调用顺序也取决于在派生类中定义的顺序(自前至后),而与在派生类构造函数的成员初始化列表中给出的顺序无关。
(6) 派生类构造函数提供了将参数传递给基类构造函数的途径,以保证在基类进行初始化时能够获得必要的数据。因此,如果基类的构造函数定义了一个或多个参数时,派生类必须定义构造函数。
(7) 如果基类中定义了缺省构造函数或根本没有定义任何一个构造函数(此时,由编译器自动生成缺省构造函数)时,在派生类构造函数的定义中可以省略对基类构造函数的调用,即省略"<基类名>(<参数表>)"。
(8) 子对象的情况与基类相同。
(9) 当所有的基类和子对象的构造函数都可以省略时,可以省略派生类构造函数的成员初始化列表。
(10) 如果所有的基类和子对象构造函数都不需要参数,派生类也不需要参数时,派生类构造函数可以不定义。
(11) 派生类不能继承基类的构造函数和析构函数。
派生类的析构函数
如果基类是多态类,则基类的析构函数必须是虚函数否则可能会造成内存泄露
什么时候一个类的析构函数式virtual,原则如下:
1)该类会被继承
2)该类中有其他虚函数
这两个条件都满足时,析构函数才会需要时virtual。就是所谓的基类是多态类。
派生类的赋值操作符
class Base
{
public:
Base& operator=(const Base& other);
private:
int m_i,m_j,m_k;
};
class Derived:public Base
{
public:
Derived& operator=(const Derived& other);
private:
int m_x,m_y,m_z;
};
Derived& Derived::operator=(const Derived& other)
{
if(this != other)
{
Base::operator=(other);//因为不能直接对基类的私有成员进行赋值。
m_x = other.m_x;
m_y = other.m_y;
m_z = other.m_z;
}
return *this
}