18.3节练习

练习18.21 解释下列声明的含义,在它们当中存在错误吗?如果有,请指出来并说明错误的原因。

(a) class CADVehicle : public CAD, Vehicle{...}    //无错误,私有继承Vehicle

(b) class DblList : public List, public List{...}    //一个基类只能继承一次

(c) class iostream : public istream, public ostream{...}    //无错误


练习18.22 已知存在如下所示的类的继承体系,其中每个类都定义了一个默认构造函数:

class A{...};
class B :public A { ... };
class C :public B { ... };
class X { ... };
class Y { ... };
class Z :public X, public Y { ... };
class MI :public C, public Z { ... };
对于下面的定义来说,构造函数的执行顺序是怎样的?

MI mi;

A-B-C-X-Y-Z-MI


练习18.23 使用练习18.22的继承体系以及下面定义的类D,同时假定每个类都定义了默认构造函数,请问下面的哪些类型转换是不被允许的?

class D : public X, public C{...};

D* pd = new D;

(a) X* px = pd;    t

(b) A* pa = pd;    t

(c) B* pb = pd;    t

(d) C* pc = pd;    t


练习18.24 在第714页,我们使用一个指向Panda对象的Bear指针进行了一系列调用,假设我们使用的是一个指向Panda对象ZooAnimal指针将发生什么情况,对这些调用语句逐一说明。

ZooAnimal* pz = new Panda("panda");

pz->print();            //正确,调用Panda::print();

pz->cuddle();         //正确,调用Panda::cuddle();

pz->highlight();       //错误,不属于ZooAnimal的接口

delete pz;                //正确,调用Panda::~Panda()


练习18.25 假设我们两个基类Base1和Base2,它们各自定义了一个名为print的虚成员和一个虚析构函数。从这两个基类中派生出下面的类,它们都重新定义了print函数:
class D1 : public Base1 {...};

class D2 : public Base2 {...};

class MI : public public D1, publuc D2 {...};

通过下面的指针,指出在每个调用中分别使用了哪个函数:

Base1* pb1 = new MI;

Base2 *pb2 = new MI;

D1* pd1 = new MI;

D2* pd2 = new MI;

(a) pb1->print();    //MI::print()

(b) pd1->print();    //MI::print()

(c) pd2->print();    //MI::print()

(d) delete pb2;    //MI::~MI() , D2::~D2(), Base2::~Base2(), D1::~D1(), Base1::~Base1()

(e) delete pd1;    //如上

(f) delete pd2;    //如上


测试程序:

#include <iostream>
#include <string>
#include <memory>
using namespace std;
class Base1 {
public:
	virtual void print() { cout << "Base1 print()" << endl; }
	virtual ~Base1() { cout << "Base1 ~" << endl; }
};
class Base2 {
public:
	virtual void print() { cout << "Base2 print()" << endl; }
	virtual ~Base2() { cout << "Base2 ~" << endl; }
};
class D1:public Base1 {
public:
	virtual void print() { cout << "D1 print()" << endl; }
	virtual ~D1() { cout << "D1 ~" << endl; }
};
class D2 :public Base2 {
public:
	virtual void print() { cout << "D2 print()" << endl; }
	virtual ~D2() { cout << "D2 ~" << endl; }
};
class MI :public D1,public D2 {
public:
	virtual void print() { cout << "MI print()" << endl; }
	virtual ~MI() { cout << "MI ~" << endl; }
};
int main()
{
	Base1* pb1 = new MI;
	Base2* pb2 = new MI;
	D1* pd1 = new MI;
	D2* pd2 = new MI;
	pb1->print();
	pd1->print();
	pd2->print();
	//delete pb2;
	//delete pd1;
	delete pd2;
}

#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Base1 {
	void print(int) const { cout << "Base1 print(int) const" << endl; }
protected:
	int ival;
	double dval;
	char cval;
private:
	int* id;
};
struct Base2 {
	void print(double) const { cout << "Base2 print(double) cont" << endl; }
protected:
	double fval;
private:
	double dval;
};
struct Derived :public Base1 {
	void print(std::string) const { cout << "Derived print(string) const" << endl; }
protected:
	std::string sval;
	double dval;
};
struct MI :public Derived, public Base2 {
	void print(std::vector<double>) { cout << "MI print(vector<int>)" << endl; }
protected:
	int* val;
	std::vector<double> dvec;
};

练习18.26 已知如上所示的继承体系,下面对print的调用为什么是错误的?适当修改MI,令其对print的调用可以编译通过并正确执行。

MI mi;

mi.print(42);    //无法从vector<double>向int的转换。

void print(int) { cout << "MI print(int)" << endl; }

练习18.27 已知如上所示的继承体系,同时假定为MI添加了一个名为foo的函数:

int ival;
double dval;
void MI::foo(double cval)
{
	int val;
	//练习中的问题发生在此处
}

(a) 列出在MI::foo中可见的所有名字。

foo::ival.cval

MI::ival dvec print foo

Derived::print sval dval

Base1::print ival dval cval

Base2::print fval

(b) 是否存在某个可见的名字是继承多个基类的。

ival print dval cval

(c) 将Base1的dval成员与Derived的dval成员求和后赋给dval的局部实例。

	void MI::foo(double cval)
	{
		int dval;
		dval = Base1::dval + Derived::dval; 
		Base2::fval = MI::dvec.back();
		Derived::sval[0] = Base1::cval;
	}

(d) 将MI::dvec的最后一个元素的值赋给Base2::fval。

如上

(e) 将从Base1继承的cval赋给Derived继承的sval的第一个字符。

如上


练习18.28 已知存在如下的继承体系,在VMI类的内部哪些继承而来的成员无须前缀限定符就能直接访问?哪些必须要有限定符才能访问?说明你的原因。

#include <iostream>
#include <string>
using namespace std;
struct Base {
	void bar(int) { cout << "Base bar()" << endl; }		//需要限定符,否则被Derived1覆盖
protected:
	int ival = 0;		//需要访问限定符
};
struct Derived1 :virtual public Base {
	void bar(char) { cout << "Derived1 bar()" << endl; }	//不需要限定符
	void foo(string) { cout << "Derived1 foo()" << endl; }	//需要访问限定符,与Derived2的foo()产生二义性 
protected:
	char cval = '1';		//需要访问限定符,与Derived2的cval产生二义性
};
struct Derived2 : virtual public Base{
	void foo(int) { cout << "Derived2 foo()" << endl; }		//需要访问限定符
protected:
	int ival = 2;		//无须访问限定符,覆盖基类的ival
	char cval = '2';	//需要
};
class VMI:public Derived1,public Derived2{
public:
	void use()
	{
		bar(1);
		bar('c');
		Derived1::foo("hello");
		Derived2::foo(1);
		cout << ival << endl;
		cout << Base::ival << endl;
		cout << Derived1::cval << endl;
	}
};
int main()
{
	VMI vmi;
	vmi.use();
}

练习18.29 已知有如下所示的类继承关系:

class Class {...};

class Base : public Class {...};

class D1 : virtual public Base {...};

class D2 : virtual public Base {...};

class MI : public D1, public D2 {...};

class Final :public MI, public Class {...};

(a) 当作用于一个Final对象时,构造函数和析构函数的执行次序分别是什么?

构造函数:Class(), Base(), D1(), D2(), MI(), Class(), Final()

析构函数:与上述次序相反。

(b) 在一个Final对象中有几个Base()部分?几个Class部分?

1个,2个

(c) 下面的那些赋值运算符将造成编译错误?

Base* pb;    Class* pc;     MI* pmi;     D2* pd2;

(a) pb = new Class;   错误,不能将基类转换成派生类。

(b) pc = new Final; 正确

(c) pmi = pb;   错误

(d) pd2 = pmi; 正确


练习18.30 在Base中定义一个默认构造函数、一个拷贝构造函数和一个接受int形参的构造函数。在每个派生类中分别定义这三种构造函数,每个构造函数应该使用它的实参舒适化其Base部分。

#include <iostream>
using namespace std;
class Class {
	//...
};
class Base:public Class {
public:
	Base() :ival(0),Class(){}
	Base(const Base& b) :ival(b.ival) {}
	Base(int val):ival(val),Class(){}
protected:
	int ival;
};
class D1 :virtual public Base {
public:
	D1() : Base() {}
	D1(const D1& d1) = default;
	D1(int val) : Base(val) {}
};
class D2 :virtual public Base {
public:
	D2() :Base() {}
	D2(const D2& d2) = default;
	D2(int val) :Base(val) {}
};
class MI :public D1, public D2 {
public:
	MI() :D1(), D2() {}
	MI(const MI& mi) = default;
	MI(int val) : D1(val), D2(val) {}
};
class Final : public MI, public Class {
	Final() :MI(), Class() {}
	Final(const Final& f) = default;
	Final(int val) :MI(val), Class(){}
};


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值