Effective C++ 读书笔记9(32~34)
来源:互联网 发布:推广电脑软件赚钱 编辑:程序博客网 时间:2024/06/08 16:09
6 继承与面向对象设计
条款32:确定你的public集成塑模出is-a关系
请记住:
public继承意味is-a,适用于base classes深证的每一件事情也一定适用于derived classes身上,因为每一个derived class对象也都是一个base class对象
条款33:避免遮掩继承而来的名称
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();};void Derived::mf4(){mf2();}Base的作用域: mf1(1个函数);mf2(1个函数);mf3(1个函数);
Derived作用域:mf1(1个函数);mf4(1个函数);
对于mf4的实现,当编译器看到mf2,会查找各作用域,看看有没有某个名为mf2的声名式。首先查找local作用域,然后查找Derived作用域,然后查找base作用域。
看下边的例子,这次重载mf1和mf3,并添加新版mf3到Derived中去:
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作用域:mf1(2个函数);mf2(1个函数);mf3(2个函数);
Derived作用域:mf1(1个函数);mf3(1个函数);mf4(1个函数);
从名称观点来看,Base::mf1和Base::mf2不再被Derived继承:
Derived d;
int x;
d.mf1();
d.mf1(x); //错误,Derived::mf1遮盖了Base::mf1
d.mf2();
d.mf3();
d.mf3(x); //错误,Derived::mf3遮掩了Base::mf3
如你所见,上述规则依然适用,即使函数参数不同。
这些行为背后的理由是为了防止你在程序库或应用框架内建立新的derived类时附带的从base 类继承重载函数,但有时你通常会想继承重载函数。实际上如果你正在使用的public继承而又不继承那些重载函数,就是违反了is-a关系,那么该怎么办呢?可以使用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;using Base::mf3;virtual void mf1();void mf3();void mf4();};
Base作用域:mf1(2个函数);mf2(1个函数);mf3(2个函数);
Derived作用域:mf1(2个函数);mf3(2个函数);mf4(1个函数);
此时:
Derived d;
int x;
d.mf1();
d.mf1(x); //ok,调用Base::mf1
d.mf2();
d.mf3();
d.mf3(x); //ok,调用Base::mf3
请记住:
1.derived类内的名称会遮掩base类的名称。在public继承下没有人希望如此。
2.为了让被遮掩的名称重见天日,可以使用using声明式或转交函数(forwarding functions)
条款34:区分接口继承和实现继承
作为类设计者:
1.有时希望derived类只继承成员函数的接口;
2.有时希望继承函数的接口和实现,但又希望能够override所继承的实现;
3.有时希望derived class同时继承函数的接口和实现;
class Shape{public:virtual void draw() const = 0;virtual void error(const std::string& msg);int objectID() const;};class Rectangle: public Shape{};class Ellipse: public Shape{};
1.成员函数的接口总是会被继承。
Shape的三个函数类型不同,有什么样的暗示呢?
1.1 生命一个pure virtual函数的目的是为了让derived类只继承函数接口。
令人意外的是,我们竟然可以为pure virtual函数提供定义,也就是说你可以为shape::draw提供一份实现代码,C++并不会发出怨言,但调用它的唯一途径是调用时明确指出其类名:
Shape* ps = new Shape; //错误,shape是抽象的Shape* ps1 = new Rectangle;ps1->draw();Shape* ps2 = new Ellipse;ps2->draw();ps1->Shape::draw(); //调用Shape::drawps2->Shape::draw(); //调用Shape::draw1.2生命一般虚函数的目的,是让derived classes继承该函数的接口和缺省实现。
但是,允许一般虚函数同时指定函数声明和缺省行为,却有可能造成危险:
class Airport{};class Airplane{public:virtual void fly(const Airport& destination);//...};void Airplane::fly(const Airport& destination){//default code, fly to destination}class ModelA: public Airplane{};class ModelB: public Airplane{};
此处的fly函数为普通虚函数,有缺省的实现。A和B类型飞机如果不重写fly函数,就会继承之。如果又来了一个新款的C飞机,其实并不想按照缺省的实现飞行,但是又忘了自己写实现,那么就会继承缺省实现,但新款飞机用缺省实现飞出来的效果可能并不好。怎么办?
class Airplane{public:virtual void fly(const Airport& destination) = 0;//...protected:void defaultFly(const Airport& destination);};void Airplane::defaultFly(const Airport& destination){//default code, fly to destination}
好了,若想使用缺省实现(A和B),可以在其fly函数中对defaultFly做一个inline调用:
class ModelA: public Airplane{public:virtual void fly(const Airport& destination){defaultFly(destination);}};class ModelB: public Airplane{public:virtual void fly(const Airport& destination){defaultFly(destination);}};
现在C不可能意外的继承不正确的fly实现代码了,因为AirPlane中的pure virtual函数迫使C必须提供自己的fly版本。
(如果把fly声明为pure的,那么所有的derived类都不能随意继承fly了,所有这里这样搞一下有意义吗?)
1.3 声明non-virtual函数的目的是为了令derived class继承函数的接口及一份强制性实现。
请记住:
1.接口继承和实现继承不同。在public继承之下,derived class总是继承base class的接口。
2.pure virtual函数只具体指定接口继承。
3.non-virtual函数具体指定接口继承及缺省实现继承。
4.non-virtual函数具体指定接口继承以及强制性实现继承。
- Effective C++ 读书笔记9(32~34)
- <<Effective C++>>读书笔记9: 杂项讨论
- 《Effective C++》读书笔记
- 《Effective C++》读书笔记
- 《Effective c++》读书笔记
- 《more effective c++》读书笔记
- <<effective c++>> 读书笔记
- 《Effective C++》读书笔记
- 《Effective C++》读书笔记
- Effective C++(1)读书笔记
- Effective C++(2)读书笔记
- 《Effective C++》读书笔记
- 《Effective C++》读书笔记
- 《effective c++》读书笔记【一】
- 《effective c++》读书笔记1
- 《effective c++》读书笔记2
- 《effective c++》读书笔记3
- 《effective c++》读书笔记4
- Spring mvc (七) [基于注解@RequestMapping(method=)限制请求为get或者post]
- IE,FF下JS闭包的资源释放差异
- 练习笔记01
- 数据结构小总
- 练习笔记02
- Effective C++ 读书笔记9(32~34)
- 在word中实现代码的语法高亮
- 笔记:Gof设计模式--Façade
- Android中处理异常——代码
- Linux目录配置标准FHS
- How to find Mister/Miss right
- [IOC] StructureMap的疑惑。
- 【Andorid应用开发】-(1)博客总结,记在专栏之前
- Ubuntu太牛了!