Effective C++读书笔记
条款32:确定public继承塑造出is-a关系
如果你另class D以public形式继承class B,你便告诉编译器(以及你的代码阅读者)说,你D的每一个对象同时也是类型为B的一个对象.
public继承遇到的问题:
class Bird{ public: virtual void fly(); //bird can fly ... }; class Penguin:public Bird{ //Penguin is a kind of bird ... };企鹅(penguin)是一种鸟是事实,鸟可以飞也是事实,但这个继承体系说企鹅可以飞,显然不严谨
既然不是所有的鸟都可以飞,就这样处理继承体系:
class Bird{ ...//没有声明fly函数 }; class FlyingBird:public Bird{ public: virtual void fly(); ... }; class Penguin:public Bird{ ... //没有声明fly函数 };
存在于classes之间的关系,is-a,has-a,is-implemented-in-terms-of(根据某物实现出)
请记住:
★★"public继承"因为is-a.适用于base class身上的每一件事情一定也适用与derived class身上,因为每一个derived class对象也都是一个base class对象.
条款33,避免遮掩,继承而来的名称
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();
void mf4();
};
以作用域为基础的“名称遮掩规则”并没有改变,因此base class内所有名为mf1和mf3的函数都被derived class内的mf1和mf3函数遮掩掉了。
Derived d;
int x;
d.mf1();
d.mf1(x);//错误,Derived::mf1遮掩了Base::mf1
d.mf2(); //调用base::mf2()
d.mf3();
d.mf3(x);//错误,Derived::mf3遮掩了Base::mf3
即使base class和derived classes内的函数有不同的参数类型也适用,而且不论函数是virtual或non-virtual也适用,和函数里的double x遮掩全局int x一样,Derived内的函数mf3遮掩了一个名称为mf3但类型不同的函数
这些事防止你建立derived class时附带的从疏远的base classes继承重载函数,如果想继承重载函数 则使用using
列:
你可以用using声明式达成目标:
class Derived : public Base { public: //base class内的public名称在publicly derived class内也应该是public。 using Base::mf1; // 让base class内为mf1和mf3的所有东西 using Base::mf3; //在Derived class作用域内都可见(并且public) virtual void mf1(); void mf3(); void mf4(); }; Derived d; int x; d.mf1(); d.mf1(x);//现在没问题了,调用Base::mf1 d.mf2(); d.mf3(); d.mf3(x);//现在没问题了,调用Base::mf3
这意味着如果你继承base class并加上重载函数,而你又希望重新定义或覆写(推翻)其中一部分,那么你必须为那些原本会被覆盖的每一个名称引入一个using声明式,否则某些你希望继承的名称会被覆盖。
★假设Derived以private形式继承Base,而Derived唯一想继承mf1是哪个无参数版本,using声明将排不上用场,因为using声明会令继承而来的某给定名称之所有同名函数在derived class中都可见,实现这一功能需要不同的技术:转交函数(forwarding function)
class Base{ public: virtual void mf1() = 0; virtual void mf1(int); ...//与前同 }; class Derived:private Base { public: virtual void mf1() { Base::mf1(); } ... }; ... Derived D; int x = 10; D.mf1();//很好,调用的是Derived::mf1() D.mf1(x)//错误Base::mf1()被遮掩了