练习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(){}
};