练习15.18
假设给定了第543页和544页的类,同时已知每个对象的类型如注释所示,判断下面的哪些赋值语句是合法的。解释哪些不合法的语句为什么不被允许:
Base *p = &d1; // d1的类型是Pub_Derv
p = &d2; // d2的类型是Priv_Derv
p = &d3; // d3的类型是Prot_Derv
p = &dd1; // dd1的类型是Derived_from_Public
p = &dd2; //dd2 的类型是Derived_from_Private
p = &dd3; //dd3 的类型是Derived_from_Protected
解答:
class Base{
public:
Base() = default;
void pub_mem(){};
protected:
int prot_mem;
private:
char priv_mem;
};
struct Pub_Derv: public Base{
int f(){return prot_mem;}
};
struct Priv_Derv: private Base{
int f1() const {return prot_mem;}
};
struct Prot_Derv: protected Base{
int f2() const {return prot_mem;}
};
struct Derived_from_Public : public Pub_Derv{
int use_base(){return prot_mem;}
};
struct Derived_from_Private: public Priv_Derv{
};
struct Derived_from_Protected: public Prot_Derv{
int use_base(){return prot_mem;}
};
Pub_Derv d1;
Priv_Derv d2;
Prot_Derv d3;
Derived_from_Public dd1;
Derived_from_Private dd2;
Derived_from_Protected dd3;
以上是各个类的定义 Base *p = &d1; // 合法
p = &d2; // error: ‘Base’ is an inaccessible base of ‘Priv_Derv’
p = &d3; // error: ‘Base’ is an inaccessible base of ‘Prot_Derv’
p = &dd1; // 合法
p = &dd2; // error: ‘Base’ is an inaccessible base of ‘Derived_from_Private’
p = &dd3; // error:‘Base’ is an inaccessible base of ‘Derived_from_Protected’
练习15.19
假设543页和544页的每个类都有如下形式的成员函数:
void memfcn(Base &b){b = *this;}
对于每个类,分别判断上面的函数是否合法。
解答:
这个题稍稍有点绕,不过画个继承关系图,就很容易看出来了。(我用眼睛看了半天……悲剧的)
这里Pub_Derv、Priv_Derv、Prot_Derv,因为是直接继承于Base,所以做这个赋值操作肯定没有问题。
如果加入这个函数编译出现问题,那么一定在Derived_from_*类里面。
在Derived_from_*类里面Base可以看做一个成员,根据*_Derv的继承方式来来决定修饰符。
比如:Prot_Derv类以protected的方式继承Base,在Derived_from_Protected继承过程中中,就可以把Base当做Prot_Derv的一个protect的成员。
(我是这样理解的,不知道有没有更好的解释方式)
Derived_from_Public继承于Pub_Derv, Base相当于public成员,直接访问赋值没有问题。
Derived_from_Protected继承于Prot_Derv, Base相当于protected成员,直接访问赋值没有问题。
Derived_from_Private继承于Priv_Derv, Base相当于private成员,直接访问赋值有问题。
所以,在Derived_from_Private中添加以上函数就是非法的。
练习15.20
编写代码验证你得对前面两题的回答是否正确。
解答:
19题的错误信息:(from g++ 4.9.1)
error: ‘Base’ is an inaccessible base of ‘Derived_from_Private’
练习15.21
从下面这些一般性抽象概念中任选一个(或者选一个你自己的),将其对应的一组类型组支撑一个继承体系:
(a) 图形文件格式(如gif,tiff,jpeg,bmp)
(b) 图形基元(如方格,圆,球,圆锥)
(c) C++语言中的类型(如类,函数,成员函数)
解答:
这里图形基元应该更加直观一些,建议选这个吧。
比如圆吧,(我们的圆需要建立在笛卡尔坐标系中)
圆的最基本元素就是半径和远点,但是这只能被用于正圆。
我们希望圆的基元也能涵盖到椭圆,因为我们知道正圆是椭圆的一种特例。
所以,就要扩充圆点和半径等内容,肯那个就需要添加焦点,准线之类的成员变量。
当然,之后还需要去计算面积,重置一些成员变量,这时候就需要定义我们需要的成员函数了。
struct Point{
double x;
double y;
};
class cricle{
public:
cricle() = default;
virtual double area() = 0;
virtual double circumference() = 0;
private:
Point p;
};
椭圆可以继承这个基类。
尝试着实现了下椭圆的类,发现就是个坑呀,把高中数学复习了一下,忘得几乎差不多了,这里也就不放上来了(有点怀念matlib了)
PS 个人感觉这个基类也实现的不好,不过,格式上大家还是可以参照一下的。
练习15.22
对于你再上一题中选择的类,为其添加合适的虚函数及公有成员和受保护的成员。
解答:
这题就考虑要对类做一定的封装了。
当然,这个开始的时候大家可以随意设置,权当做练习。
但当涉及到真正的程序设计,就需要你去按照实际考虑哪些成员需要哪些修饰符进行修饰。