![面向对象程序设计及C++实验指导(第3版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/255/43696255/b_43696255.jpg)
第5章 继承性
1.例5-3的思考题:
如果将例5-3中的语句“Member mem;”从Derived类移至Base类中,运行结果会发生何种变化?
【分析与解答】创建obj时,系统将首先调用基类Base对象成员mem的构造函数,再调用Base的构造函数,最后调用Derived的构造函数。析构函数的执行次序与此相反。
修改后代码如下。
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/017-2-i.jpg?sign=1739420920-2IsqkgV3R14C10IbY1s57x3klZPTa9Wx-0-3945c058b501f11d3faf91e7f033c594)
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/018-i.jpg?sign=1739420920-87THYjwIu0ftVazhg4tXX2txOWuFWMis-0-6c2b807f880af668c1f64a7a1186cbbd)
程序运行结果如下。
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/018-2-i.jpg?sign=1739420920-66FFljdwuPGghmXgA5vSRj2lzShufLOD-0-34c567b1ce5759cc96b3dbec6dc2c54a)
2.例5-4的思考题:
①如果将例5-4中Derived类的构造函数改为如下形式,是否可行?
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/018-3-i.jpg?sign=1739420920-PP93WRK1rNDT5hckRey1C21m9x4NYOfS-0-38c0fedf689df3056977418fe2ee507f)
②如果将Base类构造函数的声明改为如下形式,那么①中的改动是否可行?
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/018-4-i.jpg?sign=1739420920-xGEIczUU5zewTkmeZe89yo1M5alkCiXl-0-36cab40373ad36143e1d39f966527a63)
③在Derived中共有两个x:一个是Derived继承自Base的x,另一个是对象成员d中的x,运行结果中的“x=100”输出的是哪一个x的值?
④在main()函数中能否使用obj.d.show()输出d中x的值?
【分析与解答】①C++规定基类的构造函数必须由派生类的构造函数来调用。如果初始化表中没有调用,系统将调用无参或默认参数的构造函数。本例中,Base类并没有提供这类构造函数,因此会发生语法错误,故不可行。
②从语法上看这样处理可以解决①的问题。但直接把Base(i)移入Derived的构造函数中,编译器会认为这里在重新定义一个形参i,它将其视作重复定义i,并给出一个语法错误。如果将这里的Base(i)改为Base(i+1)或者Base(6)可以消除语法错误。但对于程序设计者来说仍然达不到最初的目标。程序员的动机是给Derived类中继承自Base的成员x赋一个值。但实际上程序的执行效果是产生一个临时对象,并用i+1或者6赋值给临时对象的x,并且这一行执行完后临时对象马上就被析构。Derived类中的x仍是默认的值0。
如果将Base(i)改为“x=i”是否可行呢?仍然不可行,因为x是Base中的私有成员。如果x是一个公有或保护成员,那么这样处理从语法上来看是可行的,但不推荐这么做。
③show()中的语句“cout<<"x="<<x<<endl;”输出的是变量x,即继承自Base的x。
④不可以,因为d是Derived中的私有成员,外界无法访问。
3.例5-9的思考题:
如果将例5-9中Derived类构造函数的下述两条语句删除,并且Base1、Base2中只有一个类将Base声明为虚基类,那么程序的运行结果将如何变化?
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/019-i.jpg?sign=1739420920-3NKaVmsOx60qj6YXte6bZrsatb0A2d0I-0-e1c5d1a6935835cf2faf00428f174b55)
【分析与解答】假设Base2将Base声明为虚基类,那么程序运行时,首先由Derived调用虚基类Base的构造函数,然后调用Base1基类Base的构造函数,再依次调用Base1和Base2的构造函数,最后调用Derived的构造函数。析构函数的调用次序与之相反。
假设Base1将Base声明为虚基类,那么程序运行时,首先由Derived调用虚基类Base的构造函数,然后调用Base1的构造函数,再调用Base2基类Base的构造函数,最后调用Base2和Derived的构造函数。析构函数的调用次序与之相反。
从上述讨论可以看出,两种情况下构造函数的执行次序并不一样,程序的运行结果也不相同。
(注:VS 2010下这样修改后有编译错误,应是VS 2010的bug)
①若Base2将Base声明为虚基类,则运行结果如下。
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/019-2-i.jpg?sign=1739420920-l6yDWgs1bmUBzbW1LVzclMl5jJtTKraB-0-8dccef7990645536f9967c08dfcdf8c8)
②若Base1将Base声明为虚基类,则运行结果如下。
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/019-3-i.jpg?sign=1739420920-ihUOboS0CUWO16EssMj98UshGbqo4OFa-0-67e8d57b657bbb1ebab7e527c10df651)
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/020-i.jpg?sign=1739420920-Fp6PK9wzqPMrOJpm7Y0Db1oKJHKagXVY-0-422df3629393787431be3692f927f880)