关于C++继承体系中类的构造与析构的顺序【转贴】

                                          关于C++继承体系中类的构造与析构的顺序
1.构造函数
先看下面的类定义
class B1                        class B2
{                                {
public:                                public:
        int i;                                int i;
        B1() { i = 0; }                 B2() { i = 0; }
        virtual void f() {}             virtual void f() {}
} ;                               } ;

 

class M1                        class M2
{                                {
public:                                public:
        int i;                                int i;
        M1() { i = 0; }                        M2() { i = 0; }
        virtual void mf() {}                virtual void mf() {}
} ;                               };

class C : public B1, public B2
{
public:
        virtual void f() {}
        M1 m1;
        M2 m2;
};

(1)编译器会不会为C生成默认构造(default ctor)
        编译器只在需要时才会为一个类生成def ctor。“需要时”指:
        a.一个类有虚函数
        b.一个类有虚基类
        c.一个类的基类有def ctor
        d.一个类的成员类有def ctor
        在这里,class C符合c,d两个条件,编译器会为它生成def ctor.

(2)默认构造的内容
        编译器生成的def ctor是这样的
        C::C()
        {
                B1::B1()
                B2::B2()
                设定虚表指针指向C的虚表
                m1::M1()
                m2::M2()
        }
        a.按声明顺序构造基类
        b.设定虚表指针
        c.按声明顺序构造成员类

(3)对自定义构造函数的改造
        对于B1,B2,M1,M2,已有构造函数,但编译器会对其改造,加入一些代码,完成必要的初始化工作。改造后的ctor如下:(以B1为例)
        B1::B1()
        {
                设定虚表指针指向B1的虚表
                i = 0;
        }
        a.设定虚表指针
        b.如果用户写有代码(如i=0),则执行这些代码

(4)综合(2),(3),构造函数完整代码如下
        T::T()
        {
                按声明顺序构造基类
                设定虚表指针
                按声明顺序构造成员类
                如果用户写有代码,则执行这些代码
        }
        在用户代码执行前,基类与成员类已构造完毕,虚指针已设定。

        所以C的构造顺序是:B1-〉B2-〉虚指针设定-〉m1-〉m2->C自己的代码(如果有的话)
        由(3)可知,每个类的ctor中,都会暂时将虚指针指向自己的虚表。调用B1::B1时,虚指针指向B1的虚表,然后在C::C中,虚指针被重新设定为C的虚表。
        在继承体系中,构造是由上而下的,B1或B2构造时,C还未构造。C构造时,B1和B2已构造完成。

        所以在继承体系中,一个类的构造函数执行时,该类的所有基类已构造完毕,虚指针已设定,所有成员类也已构造完毕。但该类的所有子类均未构造完成。

 

 

2.析构函数
(1)编译器会不会为C生成析构函数(dtor)
        编译器只在需要时才会为一个类生成dtor。“需要时”指:
        a.类的基类有析构
        b.类的成员类有析构
        与构造不同,少了两点,因为在一个类析构时,这是一个破坏操作(destory),既然类以已经没用了,何必再把虚指针设一下呢。

 

(2)析构的内容
        编译器生成的析构是这样的
        C::~C()
        {
                m2::M2()
                m1::M1()
                B2::B2()
                B1::B1()
        }
        a.按声明顺序相反的顺序析构成员类
        b.按声明顺序相反的顺序析构基类
        这里的相反顺序是C++标准规定的要求,不同编译器都应做到,否则不符合标准(实际上编译器或多或少都有不符标准的地方,当然不是指这里所说的顺序问题)

(3)完整的析构的调用顺序
        对于已有析构函数的类,编译器会对其改造,加入一些代码,完成必要的工作。改造后的dtor如下:
        T::~T()
        {
                设定虚表指针指向T的虚表
                执行用户代码
                按声明顺序相反的顺序析构成员类
                按声明顺序相反的顺序析构基类
        }
        这是完整的析构的调用顺序
        在用户代码执行前,虚指针已重新设定,以便用户代码能正确执行。然后再析构成员类和基类。

        所以,如果上面例子中的五个类都有析构函数的话,调用顺序是:
        虚指针设定-〉C自己的代码->m2-〉m1-〉B2-〉B1
        每个类的dtor中,都会暂时将虚指针指向自己的虚表。调用C::~C时,虚指针指向C的虚表,然后在B1::~B1中,虚指针被重新设定为B1的虚表。

        可见,在继承体系中,析构是由下而上的,B1或B2析构时,C已被析构。C析构时,B1和B2还未被析构。
        所以在继承体系中,一个类的析构函数执行时,该类的所有基类还未被析构,所有成员类也未被析构。但该类的所有子类均已析构完成。

 

3.虚函数
        在构造或析构中调用虚函数,会怎样.如:
        B1::B1()
        {
               f();
        }
        调用的是B1::f()还是C::f()
        答案是B1::f()
        每个类的ctor中,都会暂时将虚指针指向自己的虚表。调用B1::B1时,虚指针指向B1的虚表
        所以是B1::f()
        如果在C的构造函数中调用f(),那就调用C::f()

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值