• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C++ 派生类构造函数和析构函数

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

几个问题

一个类的各数据成员的构造顺序?

按他们在类定义中出现的先后顺序:先定义者先构造。

类的对象成员的构造函数与类自身的构造函数的执行顺序?

先执行对象成员的构造函数,再执行类自身的构造函数。

构造顺序与析构顺序的关系?
二者顺序相反:先构造者,后析构。

构造函数和析构函数用来创建和释放该类的对象,当这个类是派生类时,其对象的创建和释放应与其基类对象及成员对象相联系。
在声明派生类时,一般还应当自己定义派生类的构造函数和析构函数,因为构造函数和析构函数是不能从基类继承的

 

派生类对象的创建和初始化与基类对象的创建和初始化有关。即构造派生类对象时,要对其基类数据成员、所含对象成员的数据成员以及其他的新增数据成员一起进行初始化。这种初始化工作是由派生类的构造函数来完成的。
派生类成员包括两部分:
(1)从基类继承的成员:由基类构造函数完成
(2)自身定义的成员: 由派生类构造函数完成


 

在派生类中,构造基类数据成员的可能方式:

方式一,在派生类中直接对基类型数据成员初始化:

class BC
{
public:
    BC( )
    {
        x = y = -1;
    }
private:
    int x, y;
};
class DC : public BC
{
public:
    DC( )
    {
        x = y = -1;//错误,不能构造基类的私有成员  error C2248: “B::x”: 无法访问 private 成员(在“B”类中声明)
    }
private:
    string  S;
};

 

方式二,显示调用基类构造函数

class BC
{
public:
    BC( )
    {
        x = y = -1;
    }
private:
    int x, y;
};
class DC : public BC
{
public:
    DC( )
    {
        BC( );//这是构造后才调用,语义错误
    }
private:
    string  S;
};

这样的程序可以编译通过,但语意错误,这是派生类先构造后,在调用基类的构成函数。

 

正确构成基类数据成员的方式为:

class BC
{
public:
    BC( )
    {
        x = y = -1;
    }
private:
    int x, y;
};
class DC : public BC
{
public:
    DC( ) : BC( ), S("派生类"), { }//初始化列表
private:
    string  S;
};

在创建派生类的对象时,需要调用基类的构造函数:初始化派生类对象从基类继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数。

 

调用基类构造函数的两种方式:
(1)显式方式:在派生类的构造函数中,通过参数化表为基类的构造函数提供参数
        derived::derived(arg_derived-list):base(arg_base-list)
(2)隐式方式:在派生类/基类的构造函数都缺省时,派生类的构造函数则自动调用基类的默认构造函数。

在一个多层次的继承层次结构中,一个派生类对象的创建时,其构造函数的调用有点类似于多米诺骨牌效应 (domino effect)

 


 

 

列出了不同情况下的派生类构造函数要求:

 

 

上面的例子其实也很好理解,我们知道:在执行一个派生类的构造函数之前,总是先执行基类的构造函数。

1.如果基类中无构造函数,那么对于派生类来说,不管派生类是何种构造函数,编译器都会先调用的执行基类的缺省构造函数,然后再执行派生类的构造函数。

2.如果基类是一个无缺省参数的构造函数,那么对于派生类一旦没有构造函数,那么就不会自动的先构造基类的构造函数,这是不允许的。

3.如果基类中有缺省参数的构造函数B(),那么派生类中没有构造函数也是允许的,编译器会自动调用。

 

通常, 一个基类有一个缺省构造函数。

以下做法是有其实际意义的:当一个派生类对象被创建时会引起某个基类的构造函数的执行。
 (这条建议在派生类新增成员依赖于基类成员时体现非常明显)

class Team
{
public:
    Team(int len =100)
    {
        names = new string[maxno = len ];
        //基类构造函数完成其成员初始化,供派生类构造使用。
    }
protected:
    string* names;
    int     maxno;
};

class BaseballTeam : public Team
{
public:
    BaseballTeam(const string s[], int si)
        : Team(si)//为支持派生类构造本意,必须明确调用基类构造函数。

    {
        for(int i=0; i<si; i++)
            names[i] = s[i];
            //派生类构造函数执行前,基类构造必须完成。

    }
};

执行构造函数的顺序:

1. 基类的构造函数

2. 子对象的构造函数

3. 其他数据成员初始化

 

继承下的析构函数 Destructors Under Inheritance

 

class BC
{
public:
    BC( )
    {
        sBC = new char[3];
        cout << "BC allocates 3 bytes.\n";
    }
    ~BC( )
    {
        delete [ ] sBC;
        cout << "BC free 3 bytes.\n";
    }
private:
    char* sBC;
};
class DC : public BC
{
public:
    DC( )
    {
        sDC = new char[5];
        cout << "DC allocates 5 bytes.\n";
    }
    ~DC( )
    {
        delete [ ] sDC;
        cout << "DC free 5 bytes.\n";
    }
private:
    char* sDC;
};
int main( )
{
    DC d;
    cout << “-------” << endl;
    return 0;
}

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
C++指针详解 (转) C++指针详解发布时间:2022-07-13
下一篇:
SQL过程自动C#封装,支持从表到基本存储过程生成,发布时间:2022-07-13
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap