C+笔记八十:继承中的对象模型

依法编程Autocodes

欢迎各位小伙伴关注”依法编程“,一起交流

一、继承中的内存模型

看一个简单的程序:

#include

usingnamespacestd;

classA

{

public:

protected:

intx;

inty;

private:

};

classB:publicA

{

public:

protected:

ints;

private:

};

classC:publicB

{

public:

protected:

inth;

intv;

private:

};

intmain()

{

A objA;

B objB;

C objC;

system("pause");

return0;

}

在这个程序中,类A派生类B,类B派生类C,那么类A、B、C对象的内存模型是怎么样的呢?

类B从A类public继承,同时类B自身又增加了一个成员属性s,类C从类B公有继承,同时自身又增加了两个属性h、y。因此继承中的对象模型:

B类的内存结构就是从A类继承之后,添加自己新的成员,所以说继承中派生类拥有了基类可供访问的成员变量和成员方法,objA.x、objB.x、objC.x分配在不同的内存空间。派生类是由基类成员叠加派生类新成员得到的。

二、继承中的构造和析构

我们看类C中有类A的两个属性,有类B的一个属性,那么类C中这三个继承过来的属性是怎样进行初始化的呢?也就是说继承中如何初始化基类成员呢?基类和派生类的构造函数有什么关系呢?派生类中又是怎样初始化自己新定义的属性或方法呢?

结论:

1、在派生类对象构造时,需要调用基类构造函数对其继承得来的成员进行初始化;

2、在派生类对象析构时,需要调用基类析构函数对其继承得来的成员进行清理;

3、派生类定义一个对象时,会先调用基类的构造函数,然后再调用派生类的构造函数;

4、派生类对象进行析构时,会先调用派生类的析构函数,然后调用基类的析构函数。

继承的基类的属性由基类构造函数完成初始化,派生类新增加的属性,由派生类的构造函数完成初始化,这样使得分工明确!

三、先看一个简单的程序案例

#include

usingnamespacestd;

classA

{

public:

A()

{

cout

}

~A()

{

cout

}

protected:

intx;

inty;

private:

};

classB:publicA

{

public:

B()

{

cout

}

~B()

{

cout

}

protected:

ints;

private:

};

classC:publicB

{

public:

C()

{

cout

}

~C()

{

cout

}

protected:

inth;

intv;

private:

};

voidplay()

{

A objA;

cout

B objB;

cout

C objC;

cout

}

intmain()

{

play();

system("pause");

return0;

}

运行结果:

类A的构造函数

对象objA定义完成!

类A的构造函数

类B的构造函数

对象objB定义完成!

类A的构造函数

类B的构造函数

类C的构造函数

对象objC定义完成!

类C的析构函数

类B的析构函数

类A的析构函数

(备注:objC析构完成!)

类B的析构函数

类A的析构函数

(备注:objB析构完成!)

类A的析构函数

(备注:objA析构完成!)

请按任意键继续. . .

上面注意一点,先构造的后析构,所以最后析构时按照析构objC,析构objB,析构objA的顺序依次析构;析构派生类时按照先析构基类,后析构派生类的顺序。

四、基类含参构造函数程序案例

#include

usingnamespacestd;

classA

{

public:

A(int_x,int_y)

{

x=_x;

y=_y;

cout

}

~A()

{

cout

}

protected:

intx;

inty;

private:

};

classB:publicA

{

public:

B(inta,intb,intc):A(a,b)

{

s=c;

cout

}

~B()

{

cout

}

protected:

ints;

private:

};

voidplay()

{

A objA(1,2);

cout

B objB(3,4,5);

cout

}

intmain()

{

play();

system("pause");

return0;

}

运行结果:

类A的构造函数

对象objA定义完成!

类A的构造函数

类B的构造函数

对象objB定义完成!

类B的析构函数

类A的析构函数

类A的析构函数

请按任意键继续. . .

在基类A中,构造函数含有两个形参,这时候系统不会再提供默认的无参构造函数,我们在调用时需要传递两个参数,B类继承于A类,在用B类定义对象时,我们没有机会去对A类的构造函数传递参数。

这时候就需要使用构造函数的初始化列表来完成对基类构造函数的初始化。

五、继承中构造析构调用原则

1、派生类对象在创建时会首先调用基类的构造函数;

2、基类的构造函数执行结束后,执行派生类的构造函数;

3、当基类的构造函数有参数时,需要在子类的初始化列表中显式调用;

4、析构函数调用的先后顺序与构造函数相反。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180902A0L3ZB00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券