C++派生类的构造函数和析构函数
派生类的构造函数要点(from C++ primer plus):
1、首先创建基类对象;
2、派生类的构造函数应通过成员初始化列表将基类信息传递给基类的构造函数;
3、派生类构造函数应初始化派生类新增的数据成员。
归纳:创建基类对象(按照继承的顺序)→初始化类中新成员(按成员定义的顺序)→派生类的构造函数
#include <iostream> #include <cstring> #include <vector> #include <list> #include <string> #include <array> using namespace std; class B { public: B(void) { cout << "B\t"; } ~B(void) { cout << "~B\t"; } }; struct C { C(void) { cout << "C\t"; } ~C(void) { cout << "~C\t"; } }; struct D : B { D(){ cout << "D\t"; } ~D(){ cout << "~D\t"; } private: C c; }; int main() { D d; return 0; }
虚基类的构造函数在任何非虚基类构造函数前调用。如果继承于多个虚基类,他们的调用顺序由继承顺序为准。
#include <iostream> using namespace std; class OBJ1 { public: OBJ1(){ cout << "OBJ1\n"; } ~OBJ1(){ cout << "~OBJ1\n"; } }; class OBJ2 { public: OBJ2(){ cout << "OBJ2\n"; } ~OBJ2(){ cout << "~OBJ2\n"; } }; class Base1 { public: Base1(){ cout << "Base1\n"; } ~Base1(){ cout << "~Base1\n"; } }; class Base2 { public: Base2(){ cout << "Base2\n"; } ~Base2(){ cout << "~Base2\n"; } }; class Base3 { public: Base3(){ cout << "Base3\n"; } ~Base3(){ cout << "~Base3\n"; } }; class Base4 { public: Base4(){ cout << "Base4\n"; } ~Base4(){ cout << "~Base4\n"; } }; class Derived :public Base1, virtual public Base4, public Base3, virtual public Base2 { public: Derived() :Base4(), Base3(), Base2(), Base1(), obj2(), obj1() { cout << "Derived ok.\n"; } protected: OBJ1 obj1; OBJ2 obj2; }; int main() { Derived aa; cout << "This is ok.\n"; return 0; }
派生类的析构顺序:
#include <iostream> using namespace std; class Base { public: Base() { cout << "Base contruction" << endl; } ~Base() { cout << "Base deconstruction" << endl; } }; class Derived : public Base { int num; public: Derived(int i) { num = i; cout << "Derived contruction " << num << endl; } ~Derived() { cout << "Derived deconstruction" << num << endl; } }; int main() { Derived derived(1); cout << "------------" << endl; Base* basePtr; cout << "------------" << endl; Derived* derevedPtr; cout << "------------" << endl; basePtr = new Derived(2); cout << "------------" << endl; delete basePtr; cout << "------------" << endl; return 0; }
可以看出,当 new CDerive() 时,会先运行基类的构造函数,然后再运行派生类的构造函数;
而当 delete pointer 时,编译器只考虑 pointer 指针本身的类型而不关心 pointer 实际指向的类型,
即:若 pointer 为基类指针,则只调用基类的析构函数(不管 pointer 实际指向的是基类还是派生类);
若 pointer 是派生类指针,则先调用派生类的析构函数,再调用基类的析构函数,调用顺序与调用构造函数的顺序相反。
下面在析构函数前加关键字virtual后发现有所变化。
#include <iostream> using namespace std; class Base { public: Base() { cout << "Base contruction" << endl; } virtual ~Base() { cout << "Base deconstruction" << endl; } }; class Derived : public Base { int num; public: Derived(int i) { num = i; cout << "Derived contruction " << num << endl; } virtual ~Derived() { cout << "Derived deconstruction" << num << endl; } }; int main() { Derived derived(1); cout << "------------" << endl; Base* basePtr; cout << "------------" << endl; Derived* derevedPtr; cout << "------------" << endl; basePtr = new Derived(2); cout << "------------" << endl; delete basePtr; cout << "------------" << endl; return 0; }