32.确保你的public继承了模is-a关系

public继承意味着is-a关系(里氏替换原则),一切适用于基类也适用于派生类。

矩形继承正方形问题:

  • 可实施与矩形的操作无法实施与正方形
  • 在编程领域。正方形是一种矩形是错误的
  • 在现实领域,正方形是一种矩形是正确的

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();
}; 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

继承类函数会遮掩基类的同名函数。即使參数不同。

目的是防止继承类从基类继承重载函数。

解决方法例如以下:

class Derived:public Base {
public:
using Base::mf1;// 让Base class内mf1的全部东西在继承类作用域中都可见
using Base::mf3;
virtual void mf1();
void mf3();
void mf4();
};

为了让遮掩重见天日。可使用using声明式或者转交函数。

34.区分接口继承和实现继承

  1. 接口继承
  2. 接口和实现继承,同一时候覆写
  3. 接口和实现继承。不覆写
class Shape {
public:
virtual void draw() const = 0;// 接口继承
virtual void error(const string& msg);// 接口和实现继承。同一时候覆写
int object() const;// 接口和实现继承,不覆写
};

同意impure virtual函数同一时候指定函数声明和函数缺省行为。可能造成危急。

类A提供纯虚函数及实现fly()。期望继承类B使用fly实现,继承类C不使用fly实现。C类的实现者可能不清楚这一约定,造成类C也使用fly的实现。

解决方法:

1. 将fly改为纯虚函数。类A中实现protected defaultfly。

类B实现fly中调用defaultfly。类C实现fly。

2. 将fly改为纯虚函数,类A中提供fly的定义,类B实现的fly中调用A::fly(),类C实现fly

结论:

  • 声明为纯虚函数期望继承类仅仅继承接口。
  • 声明为虚函数目的是让继承类继承该函数的接口和缺省默认实现
  • 声明为非虚函数目的是让继承类继承函数的接口和一份强制的实现

35.考虑virtual函数以外的其它选择

  • NVI Non-Virtual Interface用来替代public virtual的方案
  • 由Function Pointers实现strategy模式
  • 古典策略模式

    遗留问题:

    tr1::function使用

36.绝不又一次定义继承而来的non-virtual函数

non-virtual代表不变性凌驾与特异性。

目的是令继承类继承函数的接口及一份强制实现

使用基类指针会调用到基类的版本号

37.绝不重定义继承而来的缺省參数

非虚函数中不同意在继承类中重定义

在虚函数中更改继承类的缺省參数不会起作用

虚函数中更改缺省參数不起作用的原因,出于效率考虑,在运行期确定參数比编译器决定慢且更为复杂

虚函数中不要提供缺省參数,虚函数改动缺省參数后,继承类要跟着改动

使用NVI(non-virtual infterace方法。non-virtual方法中提供缺省參数,no-virtaul方法调用virtual方法)

class Shape {
public:
enum ShapeColor {Red,Green,Blue};
void draw(ShapeColor color = Red) const {
doDraw(color);
}
private:
virtual void doDraw(ShapeColor color) const = 0;
};
class Rectangel:public Shape {
private:
virtual void doDraw(ShapeColor color) const;
};

38.通过复合塑模出has-a或“依据某物实现出”

复合的两层含义

  • has-a(应用域对象,比如汽车,视频画面)
  • is-implemented-in-terms-of(实现域,比如缓存器。相互排斥器)

39.明智而审慎地使用private继承

  • 假设是private继承,须要基类对象的场合。传入继承类错误,编译器不会自己主动将继承类对象转换为一个基类对象。
  • 由private继承而来的全部成员,在继承类中都会变为private
  • private继承意味着implemented-in-terms-of(依据某物实现)
  • 继承类和基类没有不论什么关系
  • private继承意味着实现被继承,接口部分被略去。private继承在设计层面没有意义
  • 和复合之间的取舍
    • 尽可能使用复合
    • 须要改动private继承基类中的虚函数时使用私有继承
    • 替代私有继承须要更改虚函数的还有一种方法: 使用复合,复合类中定义一个public继承的嵌套类,复合类使用该嵌套了的对象。
class Widget {
private:
class WidgetTimer:public Timer {
public:
virtual void OnTick() const;
};
WidgetTimer timer;
};

以上方式也能够用来阻止继承类又一次定义virtual函数

  • 使用private的还有一个场合:EBO empty base optimization空白基类最优化(STL中使用 unary_function,binary_function)

版权声明:本文博客原创文章,博客,未经同意,不得转载。

Effective C++ -- 继承和面向对象设计的更多相关文章

  1. Effective C++ —— 继承与面向对象设计(六)

    条款32 : 确定你的public继承塑模出is-a关系 以C++进行面向对象编程,最重要的一个规则是:public inheritance(公开继承)意味“is-a”(是一种)的关系.请务必牢记.当 ...

  2. Effective C++ ——继承与面向对象设计

    条款32:确定你的public继承塑模出is-a关系 以public继承的类,其父类的所有的性质都应该使用与子类,任何需要父类的地方都应该能用子类来代替,任何子类类型的对象也同时是父类的: class ...

  3. EffectiveC++ 第6章 继承与面向对象设计

    我根据自己的理解,对原文的精华部分进行了提炼,并在一些难以理解的地方加上了自己的"可能比较准确"的「翻译」. Chapter 6 继承与面向对象设计 Inheritance and ...

  4. Effective C++(20) 继承与面向对象设计

    本文主要参考<Effective C++ 3rd>中的第六章部分章节的内容. 关注的问题集中在继承.派生.virtual函数等.如: virtual? non-virtual? pure ...

  5. Effective C++: 06继承与面向对象设计

    32:确定你的public继承塑模出is-a关系 以C++进行面向对象编程,最重要的一个规则是:public继承表示的是"is-a"(是一种)的关系. 如果令class D以pub ...

  6. Effective C++ 6.继承与面向对象设计

    //条款32:确定你的public继承塑模出is-a关系 // 1.public继承意味着is-a的关系,适用在基类上的方法都能用于派生类上. //条款33:避免遮掩继承而来的名称 // 1.在pub ...

  7. Effective C++笔记:继承与面向对象设计

    关于OOP 博客地址:http://www.cnblogs.com/ronny 转载请注明出处! 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private ...

  8. Effective C++笔记(六):继承与面向对象设计

    参考:http://www.cnblogs.com/ronny/p/3756494.html 条款32:确定你的public继承塑模出is-a关系 “public继承”意味着is-a.适用于base ...

  9. 【Effective C++】继承与面向对象设计

    关于OOP 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private,也可以是virtual或non-virtual. 2,成员函数的各个选项:virtu ...

随机推荐

  1. Spring实战笔记2---Bean的装配

    创建应用对象之间协作关系的行为通常成为装配,该篇的主要内容有两个,一个Spring装配Bean的几种方式以及Spring表达式,事实上这两者是分不开的,在Spring中,对象无需自己负责查找或者创建与 ...

  2. 经常使用vi编辑命令

    进入 vi 该命令  vi filename :打开或新建文件.在第一行和第一光标  vi +n filename :打开文件,并将光标置于第 n 行首  vi + filename :打开文件,并将 ...

  3. 通过Java字节码发现有趣的内幕之String篇(上)(转)

    原文出处: jaffa 很多时候我们在编写Java代码时,判断和猜测代码问题时主要是通过运行结果来得到答案,本博文主要是想通过Java字节码的方式来进一步求证我们已知的东西.这里没有对Java字节码知 ...

  4. hdu1874畅通工程续 (dijkstra)

    Problem Description 某省自从实行了很多年的畅通工程计划后,终于修建了很多路.不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行 ...

  5. 从Rational Rose 到IBM Rational Software Architect和IBM Rational Rhapsody

    2014/10/27 RSA升级,重装,不知怎么搞的,不能添加某些图(比如,活动图),重试了几次都不行,在其它电脑上没有问题.后来把其它电脑上的workspace复制过来,问题攻克了,原来是works ...

  6. Android的目录结构说明

  7. 2-07. 素因子分解(20) (ZJUPAT 数学)

    题目链接:http://pat.zju.edu.cn/contests/ds/2-07 给定某个正整数N,求其素因子分解结果,即给出其因式分解表达式 N = p1^k1 * p2^k2 *-*pm ^ ...

  8. 安装zookeeper集群

    zookeeper集群的安装   顾名思义zookeeper就是动物园管理员,他是用来管hadoop(大象).Hive(蜜蜂).pig(小猪)的管理员, Apache Hbase和 Apache So ...

  9. veridata实验例(3)验证veridata发现insert操作不会导致同步

    veridata实验例(3)验证veridata发现insert操作不会导致同步 续接:<veridata实验举例(2)验证表BONUS与表SALGRADE两节点同步情况>,地址:点击打开 ...

  10. DBMS_STATS.GATHER_TABLE_STATS

    由于Oracle的优化器是CBO,所以对象的统计数据对执行计划的生成至关重要! 作用:DBMS_STATS.GATHER_TABLE_STATS统计表,列,索引的统计信息(默认参数下是对表进行直方图信 ...