蚂蚁的坚持

构造函数,析构函数,复制构造函数1、何时被调用1、构造函数:

a.对于栈上的对象:在编译器遇到这样的定义时Point p;会调用Point的默认构造函数(如果定义了,或者合成了)

b.对于堆上的对象:new 之后如果成功申请空间,会调用默认构造函数

c.对于静态数据区的对象:程序装载的时候会调用默认构造函数,并且对于没有初始化的数据会初始化为0

b.对于堆上的对象:new 之后如果成功申请空间,会调用默认构造函数

c.对于静态数据区的对象:程序装载的时候会调用默认构造函数,并且对于没有初始化的数据会初始化为02、析构函数:

a.对于栈上的对象:在对象退出作用域的时候

b.对于堆上的对象:在delete 对象之前

c.对于静态数据区的对象:程序关闭的时候

3、复制构造函数(不一定是调用复制构造函数,有时候是直接进行位复制操作):

a.当明显的使用一个对象对另一个对象进行初始化操作的时候:X xx = x;

b.当使用函数使用对象作为参数值传递的时候:void foo(X xx);

c.当函数传回一个对象值的时候:X foo(){X xx;…;return xx;};2、何时编译器会合成一个默认的1、构造函数:(这个是编译器需要的)a.当类中有一个或者多个成员对象带有默认构造函数时b.当类的基类带有默认构造函数时c.当类含有虚函数时:创建对象的vptr和vtbld.当类有一个虚基类时:创建虚基类的vbptr和vbtbl2、析构函数:a.当类的对象成员有析构函数时b.当类的基类有析构函数时3、复制构造函数:(合成之后除了位复制还需要其他操作)a.当类中有一个或者多个成员对象有复制构造函数时(不管是定义还是合成的)b.当类的基类有复制构造函数时c.当类含有虚函数时d.当类有一个或多个虚基类时3、合成中的调用顺序1、构造函数:(内到外)a.所有的虚基类的构造函数被调用,从最深到最浅(每一个virtual base class subobject偏移必须在执行期被存取)b.所有上一层的基类被调用,以声明顺序为顺序(多继承的时候需要调整this指针)c.初始化该类的vptr和vtbld.初始化构造函数的初始化列表中的内容(如果有基类的构造参数,则在之前传过去)e.调用未在初始化列表中的成员对象的构造函数f.调用自定义代码问题:虚基类构造的时候避免多次调用多次构造虚基类p211(添加_most_derived参数判断)问题:为什么不能在构造函数里面调用虚函数(不会有多态效果)2、析构函数:(外到内)a.调用本身的析构函数b.调用对象成员的析构函数,按声明的相反顺序c.重新设定vptr指向适当的基类的vtbld.相反顺序调用基类析构函数f.相反顺序调用虚基类的析构函数3、复制构造函数:(赋值运算符的重载)a.应该把虚基类的复制操作安插在最后,避免复制的时候被覆盖4、NRV在VS中的实践(Debug和Release的区别)class NRVTest{public:NRVTest(){cout << "NRVTest的构造函数" << endl;}~NRVTest(){cout << "NRVTest的析构函数" << endl;}NRVTest(const NRVTest&){cout << "NRVTest的复制构造函数" << endl;};NRVTest copy(){NRVTest n;return n;}/*不进行NRV优化void copy(NRVTest& _result){NRVTest n //tmpObjn::NRVTest();_result::NRVTest(n);//复制构造n::~NRVTest();//析构tmp}*//*NRV优化void copy(NRVTest& _result){_result::NRVTest();return;}*/};int main(){NRVTest obj;NRVTest copyObj = obj.copy();}Debug模式下:不使用NRV

Release模式下:使用NRV

5、构造函数的初始化列表的作用(下面情况必须使用初始化列表)a.当初始化一个ref member时b.当初始化一个const member时c.当调用一个基类的构造函数,需要一组参数时d.当调用一个成员对象的构造函数,需要一组参数时问题:为什么初始化成员对象要用初始化列表?//想想这样初始化会发生什么class Word{public:Word(){_name=0;_cnt=0;}private:String _name;int _cnt;}//被扩展//产生多余的临时对象,并且调用拷贝Word(){String tmp = String(0);_name.String::operator=(tmp);tmp::~String()_cnt = 0;}改成Word::Word():_name(0){//则扩展成//_name:String(0);_cnt = 0;}—————————————————————1、验证构造函数和析构函数的调用时刻class Con1{public:int i;};class Con2{public:Con2(){cout << "Con2的构造函数" << endl;}//提供默认构造函数~Con2(){cout << "Con2的析构函数" << endl;};int i;};Con1 globalObj;int main(){//验证3种初始化对象的情况,,访问对象数据对象的结果Con1 obj1;Con2 obj2;//cout << "无默认构造函数的数据i: " << obj1.i << endl;//链接错误cout << "有默认构造函数的数据i: " << obj2.i << endl;cout << "全局对象无默认构造函数的数据i: " << globalObj.i << endl;//验证对象的构造函数和析构函数的调用时刻{Con2 obj2;};cout << "离开作用域之后" << endl;Con2* pObj = new Con2();pObj->i = 100;cout << "pObj->i: " << pObj->i << endl;cout << "delete pObj之后" << endl;delete pObj;cout << "delete pObj之后的I值" << pObj->i << endl;pObj = NULL;}2、析构函数什么时候要声明为虚函数class ClxBase{public:ClxBase() {};~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;};void DoSomething() { cout << "Do something in class ClxBase!" << endl; };};class ClxDerived : public ClxBase{public:ClxDerived() {};~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }}; int main(){ ClxBase *p = new ClxDerived; p->DoSomething(); delete p; return 0; } 这种情况会造成内存泄漏,因为调用析构函数的时候,只调用了基类的析构函数。但如果将基类的析构函数声明为虚函数,则可以调用到子类的析构函数如果不需要基类对派生类及对象进行操作,则不能定义虚函数,因为这样会增加内存开销

看了哪些风景,遇到哪些人。尽管同学说,

蚂蚁的坚持

相关文章:

你感兴趣的文章:

标签云: