6个默认成员函数,“默认”的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类中,这几个成员函数是如何生成的呢?
- 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认 的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
- 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
- 派生类的operator=必须要调用基类的operator=完成基类的复制。
- 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
- 派生类对象初始化先调用基类构造再调派生类构造。
- 派生类对象析构清理先调用派生类析构再调基类的析构。
- 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同(这个我们后面会讲解)。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加 virtual的情况下,子类析构函数和父类析构函数构成隐藏关系。
综合例子如下:
// 这个是基类
class Person
{
public:
Person(const char* name = "peter")
: _name(name)
{
cout << "Person()" << endl;
}
Person(const Person& p)
: _name(p._name)
{
cout << "Person(const Person& p)" << endl;
}
Person& operator=(const Person & p)
{
cout << "Person operator=(const Person& p)" << endl;
if (this != &p)
_name = p._name;
return *this;
}
~Person()
{
cout << "~Person()" << endl;
}
protected:
string _name; // 姓名
};
// 这个是派生类
class Student : public Person
{
public:
Student(const char* name = "", int x = 0, const char* address = "")
:_x(x)
,_address(address)
,_name(Person::_name+'x')
,Person(name)
{}
|例:派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化
Student(const Student& st)
:Person(st)
,_x(st._x)
,_address(st._address)
{}
|例:派生类的operator=必须要调用基类的operator=完成基类的复制。
Student& operator=(const Student &st)
{
if (this != &st)
{
Person::operator= (st); |注意这里如果不显示写那么就成了隐藏 会一直调用自己
_x = st._x;
_address = st._address;
}
return *this;
}
~Student() | 析构时先子后父
{
//Person::~Person(); 会自动调用
cout << "~Student()" << endl;
}
protected :
int _x = 1;
string _address = "湖南";
string _name;
};