C++ 对象构造与析构以及内存布局

来源:互联网 发布:在淘宝买护肤品可靠吗 编辑:程序博客网 时间:2024/06/05 18:49

主要探讨对象的构造顺序与内存的布局,主要参考来源为《Exceptional C++ Style中文版》

文中第十四条 顺序!顺序!根据文中的代码摘录如下,代码中添加了一些调试的信息。

#include <map>struct classcomp {    bool operator() (const __int64& lhs, const __int64& rhs) const    {return lhs<rhs;}};std::multimap<__int64,std::string,classcomp> m_Construtor;class B1{ public:    B1()    {        std::cout<<"Constructor B1 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor B1 "));    }    virtual ~B1()    {        std::cout<<"Destructor B1 "<<this<<'\n';    }};class V1:public B1{public:    V1()    {        std::cout<<"Constructor V1 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor V1 "));    }    virtual ~V1()    {        std::cout<<"Destructor V1 "<<this<<'\n';    }};class D1:virtual public V1{public:    D1()    {        std::cout<<"Constructor D1 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor D1 "));    }    virtual ~D1()    {        std::cout<<"Destructor D1 "<<this<<'\n';    }};class B2{public:    B2()    {        std::cout<<"Constructor B2 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor B2 "));    }    virtual ~B2()    {        std::cout<<"Destructor B2 "<<this<<'\n';    }};class B3{public:    B3()    {        std::cout<<"Constructor B3 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor B3 "));    }    virtual ~B3()    {        std::cout<<"Destructor B3 "<<this<<'\n';    }};class V2:public B1,public B2{public:    V2()    {        std::cout<<"Constructor V2 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor V2 "));    }    virtual ~V2()    {        std::cout<<"Destructor V2 "<<this<<'\n';    }};class D2:public B3,virtual public V2{public:    D2()    {        std::cout<<"Constructor D2 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor D2 "));    }    virtual ~D2()    {        std::cout<<"Destructor D2 "<<this<<'\n';    }};class M1{public:    M1()    {        std::cout<<"Constructor M1 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor M1 "));    }    virtual ~M1()    {        std::cout<<"Destructor M1 "<<this<<'\n';    }};class M2{public:    M2()    {        std::cout<<"Constructor M2 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor M2 "));    }    virtual ~M2()    {        std::cout<<"Destructor M2 "<<this<<'\n';    }};class X:public D1,public D2{public:    X()    {        std::cout<<"Constructor X "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor X "));    }    virtual ~X()    {        std::cout<<"Destructor X "<<this<<'\n';    }private:    M1 _m1;    M2 _m2;};int _tmain(int argc, _TCHAR* argv[]){    //B b;    int  i;    X *pX = new X;    std::cout<<"--------------------------------------------"<<'\n';    cout.setf(ios::showbase | ios::uppercase); //设置基指示符输出和数值中的字母大写输出    std::multimap<__int64,std::string,classcomp> ::iterator iter;    for (iter = m_Construtor.begin();iter != m_Construtor.end();++iter)//遍历    {        cout<<std::hex<<(*iter).first<<"  "<<(*iter).second<<endl;    }    std::cout<<"--------------------------------------------"<<'\n';    delete pX;    pX = NULL;    std::cin>>i;return 0;}
以上程序的运行结果为:

Constructor B1 005F7F94
Constructor V1 005F7F94
Constructor B1 005F7F98
Constructor B2 005F7F9C
Constructor V2 005F7F98
Constructor D1 005F7F88
Constructor B3 005F7F80
Constructor D2 005F7F80
Constructor M1 005F7F8C
Constructor M2 005F7F90
Constructor X 005F7F80
--------------------------------------------
0X5F7F80  Constructor B3
0X5F7F80  Constructor D2
0X5F7F80  Constructor X
0X5F7F88  Constructor D1
0X5F7F8C  Constructor M1
0X5F7F90  Constructor M2
0X5F7F94  Constructor B1
0X5F7F94  Constructor V1
0X5F7F98  Constructor B1
0X5F7F98  Constructor V2
0X5F7F9C  Constructor B2
--------------------------------------------
Destructor X 005F7F80
Destructor M2 005F7F90
Destructor M1 005F7F8C
Destructor D2 005F7F80
Destructor B3 005F7F80
Destructor D1 005F7F88
Destructor V2 005F7F98
Destructor B2 005F7F9C
Destructor B1 005F7F98
Destructor V1 005F7F94
Destructor B1 005F7F94


可以看出对象的构造顺序和书中提示到的顺序一致

类图



1.首先构造虚基类子对象


2.其次构造非虚基类子对象.


3.构造成员本身


4.构造对象本身

以上同等级的构造顺序遵循从左到右的申明顺序。


但是问题出现了

问题1:这个对象X的对象内存分布是这个样子的。看上去地址是倒着分配的。首地址相近的并不是最先分配的那个对象。是个问题。。。大家可以考虑一下到底怎么分布啊???我的编译平台是VS2010

问题2:假如说类B1中含有某个方法,那么X对象调用的是哪块内存上的函数呢??

我猜是左边的那个。废话少说写测试代码。

改造一下后编译竟然发现编译问题

1>e:\opensource\exceptional c++ style\example_014class\example_014class.cpp(191): error C2385: ambiguous access of 'fun'
1>          could be the 'fun' in base 'B1'
1>          or could be the 'fun' in base 'B1'

看样子编译器他决定不了X对象将会调用内存中哪块B1的函数。


是否就没有办法了呢?

想起对象模型的那本曾提到这种情况下使用 virtual的继承 。果然请看改造后的代码。

#include <map>struct classcomp {    bool operator() (const __int64& lhs, const __int64& rhs) const    {return lhs<rhs;}};std::multimap<__int64,std::string,classcomp> m_Construtor;class B1{ public:    B1()    {        std::cout<<"Constructor B1 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor B1 "));    }    virtual ~B1()    {        std::cout<<"Destructor B1 "<<this<<'\n';    }    void fun()    {        std::cout<<"fun B1 "<<this<<'\n';    }};class V1:virtual public B1{public:    V1()    {        std::cout<<"Constructor V1 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor V1 "));    }    virtual ~V1()    {        std::cout<<"Destructor V1 "<<this<<'\n';    }};class D1:virtual public V1{public:    D1()    {        std::cout<<"Constructor D1 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor D1 "));    }    virtual ~D1()    {        std::cout<<"Destructor D1 "<<this<<'\n';    }};class B2{public:    B2()    {        std::cout<<"Constructor B2 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor B2 "));    }    virtual ~B2()    {        std::cout<<"Destructor B2 "<<this<<'\n';    }};class B3{public:    B3()    {        std::cout<<"Constructor B3 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor B3 "));    }    virtual ~B3()    {        std::cout<<"Destructor B3 "<<this<<'\n';    }};class V2:virtual public B1,public B2{public:    V2()    {        std::cout<<"Constructor V2 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor V2 "));    }    virtual ~V2()    {        std::cout<<"Destructor V2 "<<this<<'\n';    }};class D2:public B3,virtual public V2{public:    D2()    {        std::cout<<"Constructor D2 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor D2 "));    }    virtual ~D2()    {        std::cout<<"Destructor D2 "<<this<<'\n';    }};class M1{public:    M1()    {        std::cout<<"Constructor M1 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor M1 "));    }    virtual ~M1()    {        std::cout<<"Destructor M1 "<<this<<'\n';    }};class M2{public:    M2()    {        std::cout<<"Constructor M2 "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor M2 "));    }    virtual ~M2()    {        std::cout<<"Destructor M2 "<<this<<'\n';    }};class X: public D1, public D2{public:    X()    {        std::cout<<"Constructor X "<<this<<'\n';        m_Construtor.insert(std::pair<__int64,std::string>((__int64)this,"Constructor X "));    }    virtual ~X()    {        std::cout<<"Destructor X "<<this<<'\n';    }private:    M1 _m1;    M2 _m2;};int _tmain(int argc, _TCHAR* argv[]){    //B b;    int  i;    X *pX = new X;    std::cout<<"--------------------------------------------"<<'\n';    pX->fun();    std::cout<<"--------------------------------------------"<<'\n';    cout.setf(ios::showbase | ios::uppercase); //设置基指示符输出和数值中的字母大写输出    std::multimap<__int64,std::string,classcomp> ::iterator iter;    for (iter = m_Construtor.begin();iter != m_Construtor.end();++iter)//遍历    {        cout<<std::hex<<(*iter).first<<"  "<<(*iter).second<<endl;    }    std::cout<<"--------------------------------------------"<<'\n';    delete pX;    pX = NULL;    std::cin>>i;return 0;}
运行结果:

Constructor B1 00127F94
Constructor V1 00127F98
Constructor B2 00127F9C
Constructor V2 00127F9C
Constructor D1 00127F88
Constructor B3 00127F80
Constructor D2 00127F80
Constructor M1 00127F8C
Constructor M2 00127F90
Constructor X 00127F80
--------------------------------------------
fun B1 00127F94
--------------------------------------------
0X127F80  Constructor B3
0X127F80  Constructor D2
0X127F80  Constructor X
0X127F88  Constructor D1
0X127F8C  Constructor M1
0X127F90  Constructor M2
0X127F94  Constructor B1
0X127F98  Constructor V1
0X127F9C  Constructor B2
0X127F9C  Constructor V2
--------------------------------------------
Destructor X 00127F80
Destructor M2 00127F90
Destructor M1 00127F8C
Destructor D2 00127F80
Destructor B3 00127F80
Destructor D1 00127F88
Destructor V2 00127F9C
Destructor B2 00127F9C
Destructor V1 00127F98
Destructor B1 00127F94
发现类B1还少构造了一次。哈哈~~果然很强大啊。。











































原创粉丝点击