您的位置:首页 > 其它

EC读书笔记系列之15:条款32、33、34

2015-11-13 09:55 330 查看
[b]条款32 确保你的public继承塑模出is-a关系[/b]

记住:

★public继承意味着is-a。适用于base class身上的每一件事情一定也适用于derived class身上,∵每一个derived class对象也都是一个base class对象。

[b]条款33 避免遮掩继承而来的名称[/b]

记住:

★derived classes内的名称会遮掩base classes内的名称。在public继承下从来无人希望如此

★为了让被遮掩的名称再见天日,可使用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:
virtual void mf1();      //遮掩base的同名函数
void mf3();            //遮掩base的同名函数
void mf4();
...
};

Derived d;
int x;
...
d.mf1();   //正确,调用Derived::mf1
d.mf1(x);  //错!因为Derived::mf1遮掩Base::mf1
d.mf2();   //正确,调用Base::mf2
d.mf3();   //正确,调用Derived::mf3
d.mf3(x);  //错!因为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的所有东西
using Base::mf3; //在Derived作用域内都可见(且public!!!)
virtual void mf1();
void mf3();
void mf4();
...
};

Derived d;
int x;
...
d.mf1(); //仍正确,调用Derived::mf1
d.mf1(x); //没问题了!调用Base::mf1
d.mf2(); //仍正确,调用Base::mf2
d.mf3(); //仍正确,调用Derived::mf3
d.mf3(x); //没问题了!调用Base::mf3


-----------------

有时并不想继承base classes的所有函数,这是可以理解的。但这在public继承下绝不可能发生,∵其违反了public继承所暗示的is-a关系。

例如,Derived以private形式继承Base,而唯一想继承的mf1是无参版。using声明式技术此时就不行了,∵using声明式会令继承而来的某给定名称之所有同名函数在derived class中都可见。

此时需要“转交函数”技术:

class Base {
public:
virtual void mf1() = 0;    //仅想继承这个
virtual void mf1( int );
...
};

class Derived : private Base {  //注意是以private方式继承!!!而非public
public: //???有点不能理解
virtual void mf1() { //此为转交函数,暗自inline
Base::mf1();
}
...
};

Derived d;
int x;
...
d.mf1();   //正确,调用Derived::mf1(本质是里面调用Base版!!!)
d.mf1(x);  //错误!Base::mf1(int)被遮掩了,同时这也达到目的
//∵我们的目的就是唯一想继承的mf1是无参版


[b]条款34 区分接口继承和实现继承[/b]

记住:

★接口继承和实现继承不同。在public继承下,derived classes总是继承base class的接口

★纯虚函数只具体指定接口继承

★普通虚函数具体指定接口继承及缺省实现继承

★非虚函数具体指定接口继承以及强制性实现继承

------------------------------------------------

一种特殊情形:

基类的纯虚函数必须在derived classes中重新声明,且基类的纯虚函数在基类中也是可以给出详细定义的,这个定义也可以表现出一种缺省行为(那是derived class可能使用的,但只有在它们明确提出申请时才是)。

class Airplane {
public:
virtual void fly( const Airport &destination ) = 0;        //纯虚!
...
};

void Airplane::fly( const Airport &destination ) { //基类纯虚函数竟也可以提供定义!!!
//缺省行为
}

class ModelA : public Airplane {
public:
virtual void fly( const Airport &destination ) {
Airplane::fly( destination ); //derived class须明确提出申请!!!
}
...
};

class ModelB : public Airplane {
public:
virtual void fly( const Airport &destination ) {
Airplane::fly( destination ); //derived class须明确提出申请!!!
}
...
};

class ModelC : public Airplane {
public:
virtual void fly( const Airport &destination );    //ModelC自己重新定义
...
};

void ModelC::fly( const Airport &destination ) {
//属于C类型飞机自己特有的飞行方式
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: