C++中构造函数与析构函数执行顺序
2015-05-10 16:48
148 查看
C++中,当定义一个类的对象时,系统会自动的调用该类的构造函数来为对象开辟内存空间和进行初始化工作。
构造函数执行顺序:
1,先执行父类的构造函数,对父类的数据成员进行初始化。如果父类还有父类,则一直向上寻找,直到最初的基类;如果有多个父类,则构造函数执行的顺序是声明父类时的顺序,而不是初始化列表中的顺序。
2,再执行内嵌对象成员的构造函数,对对象成员进行初始化。对象成员的执行顺序是是在类中声明时的顺序,而不是初始化列表中的顺序。
3,最后在执行子类的构造函数,对子类的数据成员进行初始化。
而析构函数的调用包括以下两种情况:
(1) 当一个对象的生命周期结束时,该对象该被释放,析构函数将被自动调用。
(2) 若一个对象时使用new运算符动态创建的,在使用delete运算符释放它时,delete会自动调用析构函数。
析构函数执行顺序:
析构函数执行的顺序和构造函数刚好相反。
1,先执行子类的析构函数。
2,再执行对象成员的析构函数
3,最后执行父类的析构函数
测试例子:
测试结果:
virtual修饰的析构函数:
C++中的构造函数不能声明为虚函数;但是析构函数可以声明为虚函数,有时必须声明为虚函数。
C++中的构造函数不能声明为虚函数的原因:
(1) 创建一个对象的时候,必须要知道对象的实际类型,而虚函数的行为是在运行期间确定实际类型的,创建对象时,由于对象还没有被创建,所以编译器不知道对象的实际类型是什么。
(2) 由于虚函数的执行要依靠虚函数表,而虚函数表是在构造函数中进行初始化工作的。所以在创建对象时,虚函数表还没有被初始化,所以无法进行。
当在类的继承中,定义了一个基类的对象指针指向其派生类的对象,并用delete来释放这个指针时,如果基类的析构函数不是virtual类型的,则系统只会调用基类的析构函数,而不会调用派生类的析构函数,而最终导致内存泄露问题。
测试例子:
显然上面的运行结果不是我们想要的,它只调用了基类A的析构函数,而派生类中的析构函数并未调用,即派生类中的内存并没有得到释放,所以会出现内存泄露问题。解决方法是将基类的析构函数定义为virtual类型的即可(为了代码更加清晰,在派生类的析构函数前也加上virtual关键字):
测试例子:
构造函数执行顺序:
1,先执行父类的构造函数,对父类的数据成员进行初始化。如果父类还有父类,则一直向上寻找,直到最初的基类;如果有多个父类,则构造函数执行的顺序是声明父类时的顺序,而不是初始化列表中的顺序。
2,再执行内嵌对象成员的构造函数,对对象成员进行初始化。对象成员的执行顺序是是在类中声明时的顺序,而不是初始化列表中的顺序。
3,最后在执行子类的构造函数,对子类的数据成员进行初始化。
而析构函数的调用包括以下两种情况:
(1) 当一个对象的生命周期结束时,该对象该被释放,析构函数将被自动调用。
(2) 若一个对象时使用new运算符动态创建的,在使用delete运算符释放它时,delete会自动调用析构函数。
析构函数执行顺序:
析构函数执行的顺序和构造函数刚好相反。
1,先执行子类的析构函数。
2,再执行对象成员的析构函数
3,最后执行父类的析构函数
测试例子:
#include<iostream> using namespace std; class A { public: A(){cout<<"A-->构造函数"<<endl;} ~A(){cout<<"A-->析构函数"<<endl;} }; class B:public A { public: B(){cout<<"B-->构造函数"<<endl;} ~B(){cout<<"B-->析构函数"<<endl;} }; class C { public: C(){cout<<"C-->构造函数"<<endl;} ~C(){cout<<"C-->析构函数"<<endl;} }; class D : public B { public: D(){cout<<"D-->构造函数"<<endl;} ~D(){cout<<"D-->析构函数"<<endl;} private: C c; }; int main() { A a; B b; C c; D d; return 0; }
测试结果:
virtual修饰的析构函数:
C++中的构造函数不能声明为虚函数;但是析构函数可以声明为虚函数,有时必须声明为虚函数。
C++中的构造函数不能声明为虚函数的原因:
(1) 创建一个对象的时候,必须要知道对象的实际类型,而虚函数的行为是在运行期间确定实际类型的,创建对象时,由于对象还没有被创建,所以编译器不知道对象的实际类型是什么。
(2) 由于虚函数的执行要依靠虚函数表,而虚函数表是在构造函数中进行初始化工作的。所以在创建对象时,虚函数表还没有被初始化,所以无法进行。
当在类的继承中,定义了一个基类的对象指针指向其派生类的对象,并用delete来释放这个指针时,如果基类的析构函数不是virtual类型的,则系统只会调用基类的析构函数,而不会调用派生类的析构函数,而最终导致内存泄露问题。
测试例子:
#include<iostream> using namespace std; class A { public: A(){cout<<"A-->构造函数"<<endl;} ~A(){cout<<"A-->析构函数"<<endl;} }; class B:public A { public: B(){cout<<"B-->构造函数"<<endl;} ~B(){cout<<"B-->析构函数"<<endl;} }; class C { public: C(){cout<<"C-->构造函数"<<endl;} ~C(){cout<<"C-->析构函数"<<endl;} }; class D : public B { public: D(){cout<<"D-->构造函数"<<endl;} ~D(){cout<<"D-->析构函数"<<endl;} private: C c; }; int main() { A *a = new D; delete a; return 0; }测试结果:
显然上面的运行结果不是我们想要的,它只调用了基类A的析构函数,而派生类中的析构函数并未调用,即派生类中的内存并没有得到释放,所以会出现内存泄露问题。解决方法是将基类的析构函数定义为virtual类型的即可(为了代码更加清晰,在派生类的析构函数前也加上virtual关键字):
测试例子:
#include<iostream> using namespace std; class A { public: A(){cout<<"A-->构造函数"<<endl;} virtual ~A(){cout<<"A-->析构函数"<<endl;} }; class B:public A { public: B(){cout<<"B-->构造函数"<<endl;} virtual ~B(){cout<<"B-->析构函数"<<endl;} }; class C { public: C(){cout<<"C-->构造函数"<<endl;} virtual ~C(){cout<<"C-->析构函数"<<endl;} }; class D : public B { public: D(){cout<<"D-->构造函数"<<endl;} virtual ~D(){cout<<"D-->析构函数"<<endl;} private: C c; }; int main() { A *a = new D; delete a; return 0; }测试结果:
相关文章推荐
- C++中构造函数、析构函数的执行顺序
- C++中构造函数和析构函数(virtual)的执行顺序
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
- 浅出C++对象模型——理解构造函数、析构函数执行顺序
- C++继承时构造函数和析构函数的执行顺序
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
- c++中的类(构造函数,析构函数的执行顺序)
- c++中, 构造函数和析构函数的执行顺序
- c++ 内存申请释放,构造函数,析构函数,执行顺序
- C++在单继承、多继承、虚继承时,复制构造函数。赋值构造函数、析构函数的执行顺序
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容 【转】 参考度4.6星
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
- 宋体、构造函数-浅出C++对象模型——理解构造函数、析构函数执行顺序-by小雨
- C++-理解构造函数、析构函数执行顺序
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
- C++学习笔记(6)----基类和派生类的构造函数和析构函数的执行顺序