![面向对象程序设计及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=1739129804-aQ4BWygDDT9qu5Gmw0UHEDLodrgNZghl-0-4cbb784309d2a2fb5b9bb724ea781184)
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/018-i.jpg?sign=1739129804-3D6dEGInrZMckvMKrptToa4rMSGSB39c-0-474236b80f8fac4628bdb05ae92a1a75)
程序运行结果如下。
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/018-2-i.jpg?sign=1739129804-vwaKA55UDokurjcERLXim46pYyVkf3XS-0-f5865117624bc00c0f978db046cfb9ac)
2.例5-4的思考题:
①如果将例5-4中Derived类的构造函数改为如下形式,是否可行?
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/018-3-i.jpg?sign=1739129804-ualEXR3VJBXhLc14yMXhxiK7oq2FA10J-0-63368c59d7e64bc10ed78140b129aeaa)
②如果将Base类构造函数的声明改为如下形式,那么①中的改动是否可行?
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/018-4-i.jpg?sign=1739129804-cCbLrY8U9vdObSjR5j0tGmut6hq70n8o-0-3a94ca57bf2ddbd647a3c7831c70eec3)
③在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=1739129804-FqxBXtOJADkfy052rqGZySbfAJYzqX5A-0-2fa74c155441cd847bcbfb4cb2b76db2)
【分析与解答】假设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=1739129804-P5hPngZFGtp2iDM9NWR3kdAyiAUmyQOU-0-20fc8b1e27d9d1253e1c763505a6430b)
②若Base1将Base声明为虚基类,则运行结果如下。
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/019-3-i.jpg?sign=1739129804-bdD4mtYSfo9h4hhiosB9V8WN61PnM9Im-0-64ee0e091f279c6ed1a94bd7d45baea6)
![](https://epubservercos.yuewen.com/56F797/22987383301138006/epubprivate/OEBPS/Images/020-i.jpg?sign=1739129804-V1zJHykusnSNZeKT4MDaZZe95ioyqLux-0-3aefeafb6f89dd35fa63c21d3018f09a)