Effective C++ 条款32、33

条款32 确定你的public继承塑模出is-a关系

不用怀疑,public inheritance(公开继承)意味“is-a”(是一种)的关系。也就是说,如果令class D('Derived') 以public形式继承class B('Base'),即每一个类型为D的对象同时也是一个类型为B的对象。反之不成立。

所以在进行面向对象类设计时,需要明确继承之前是否是"is-a"关系,以决定derived类与base类设计的合理性。

举例说明,

class Person{...};
class Student:public Person{...};
void eat(const Person& p);//任何人都会吃饭
void study(const Student& s);//只有学生才到学校学习
Person p;
Student s;
eat(p);//OK,p是人
eat(s);//OK,s是学生,也是人
study(s);//学生进校学习
//以下调用存在生活常识错误
study(p);//错误,不一定所有人都进校学习
当使用public继承时,必须时刻注意不要违背这一层关系 ,如有需要,可将错误限制在编译期内,或在运行期内提示错误(没有前一点好),见下举例,
class Bird {
public:
	virtual void fly();//鸟可以飞
};
class Penguin:public Bird{//企鹅是一种鸟
};
企鹅是一种鸟,没错。但利用public继承是"is-a"关系,就不对啦。因为企鹅不会飞。于是这样定义继承关系就出现明显的逻辑漏洞。将此错误限制在编译期内的做法,
class Bird {
	//此处不声明fly函数
};
class FlyingBird :public Bird {
public:
	virtual void fly();
};
class Penguin :public Bird {//企鹅是一种鸟
	//没有声明fly函数
};
或者在运行期内提示错误,
void error(const string& msg);
class Penguin :public Bird {//企鹅是一种鸟
public:
	virtual void fly() { error("Attempt to make a penguin fly!"); }
};
is-a并非是唯一存在于classes之间的关系,另两个常见的关系是has-a(有一个,见条款38、39)和is-implemented-in-terms-of(根据某物实现出,见条款38、39)。

条款33 避免遮掩继承而来的名称

此条款需要明确了两点重要知识,其一,是类内使用using声明式,其二,名字在作用域内查找规则

有如下基类以及派生类,及图片说明其作用域范围,

class Base {
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf2();
	void mf3();
};
class Derived :public Base {
public:
	virtual void mf1();//存在覆盖基类函数现象,但具有虚函数特性
	void mf4();
};

针对derived class内的mf4的实现码,

void Derived::mf4() {
	mf2();
}
上述mf2函数,遵循的查找作用域顺序规则: 本函数内->所属派生类->所属基类->内含Base的namespace->global作用域

以下是存在遮掩继承而来的名称,

class Base {
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
	virtual void mf2();
	void mf3();
	void mf3(double);
};
class Derived :public Base {
public:
	virtual void mf1();//存在覆盖基类函数现象,但具有虚函数特性
	void mf3();//具有遮掩base内的同名函数效果
	void mf4();
};

Derived d;
int x;

d.mf1();//OK
d.mf1(x);//error!因为Derived::mf1遮掩了Base::mf1
d.mf2();//OK
d.mf3();//OK
d.mf3(x);//error!因为Derived::mf3遮掩了Base::mf3

针对上遮掩,可以在类内使用using声明式,从而打破名字被遮掩的枷锁

class Base {
private:
	int x;
public:
	virtual void mf1() = 0;
	virtual void mf1(int);
	virtual void mf2();
	void mf3();
	void mf3(double);
};
class Derived :public Base {
public:
	using Base::mf1;//让Base class内名为mf1和mf3的所有东西在Derived作用域内都可见
	using Base::mf3;
	virtual void mf1();//存在覆盖基类函数现象,但具有虚函数特性
	void mf3();//具有遮掩base内的同名函数效果
	void mf4();
};

Derived d;
int x;

d.mf1();//OK
d.mf1(x);//OK,可以调用Base::mf1
d.mf2();//OK
d.mf3();//OK
d.mf3(x);//OK,可以调用Base::mf3

以上内容均来自Scott Meyers大师所著Effective C++ version3,如有错误地方,欢迎指正!相互学习,促进!!

猜你喜欢

转载自blog.csdn.net/tt_love9527/article/details/80658449