EC读书笔记系列之15:条款32、33、34
条款32 确保你的public继承塑模出is-a关系
记住:
★public继承意味着is-a。适用于base class身上的每一件事情一定也适用于derived class身上,∵每一个derived class对象也都是一个base class对象。
条款33 避免遮掩继承而来的名称
记住:
★derived classes内的名称会遮掩base classes内的名称。在public继承下从来无人希望如此
★为了让被遮掩的名称再见天日,可使用using声明式或转交函数
-------------------------------------------------------------
编译器看到某个名称,其做法是逐层向外围查找各作用域。
-----------------------------
举个例子:
class Base {
private:
int x;
public:
virtual void mf1() = ;
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() = ;
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() = ; //仅想继承这个
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是无参版
条款34 区分接口继承和实现继承
记住:
★接口继承和实现继承不同。在public继承下,derived classes总是继承base class的接口
★纯虚函数只具体指定接口继承
★普通虚函数具体指定接口继承及缺省实现继承
★非虚函数具体指定接口继承以及强制性实现继承
------------------------------------------------
一种特殊情形:
基类的纯虚函数必须在derived classes中重新声明,且基类的纯虚函数在基类中也是可以给出详细定义的,这个定义也可以表现出一种缺省行为(那是derived class可能使用的,但只有在它们明确提出申请时才是)。
class Airplane {
public:
virtual void fly( const Airport &destination ) = ; //纯虚!
...
}; 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类型飞机自己特有的飞行方式
}
EC读书笔记系列之15:条款32、33、34的更多相关文章
- EC读书笔记系列之8:条款13、14、15
条款13 以对象管理资源 记住: ★为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放 ★两个常被使用的RAII classes分别是tr1::shared_ptr和aut ...
- EC读书笔记系列之16:条款35、36、37、38、39、40
条款35 考虑virtual函数以外的其他选择 记住: ★virtual函数的替代方案包括NVI手法及Strategy模式的多种形式.NVI手法自身是一个特殊形式的Template Method模式 ...
- EC读书笔记系列之5:条款9、条款10
条款9 绝不在构造和析构过程中调用virtual函数 记住: ★在构造和析构期间不要调用virtual函数,∵这类调用从不下降至derived class ---------------------- ...
- EC读书笔记系列之1:条款1、条款2、条款3
条款1:视C++为一个语言联邦 记住: ★C++高效编程守则视状况而变化,这取决于你使用C++的哪一部分 C: Object-oriented c++: Template c++: STL 条款2:尽 ...
- EC读书笔记系列之20:条款53、54、55
条款53 不要轻忽编译器的警告 记住: ★严肃对待编译器发出的警告信息.努力在你的编译器的最高(最严苛)警告级别下争取“无任何警告”的荣誉 ★不要过度依赖编译器的报警能力,∵不同的编译器对待事情的态度 ...
- EC读书笔记系列之19:条款49、50、51、52
条款49 了解new-handler的行为 记住: ★set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用 ★Nothrow new是一个颇为局限的工具,∵其只适用于内存 ...
- EC读书笔记系列之18:条款47、48
条款47 请使用traits classes表现类型信息 记住: ★Traits classes使得“类型相关信息”在编译期可用.它们以templates和“templates特化”完成实现 ★整合重 ...
- EC读书笔记系列之17:条款41、42、43、44、45、46
条款41 了解隐式接口与编译器多态 记住: ★classes和templates都支持接口和多态 ★对classes而言接口是显式的(explicit),以函数签名为中心.多态则是通过virtual函 ...
- EC读书笔记系列之14:条款26、27、28、29、30、31
条款26 尽可能延后变量定义式的出现时间(Lazy evaluation) 记住: ★尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率 ----------------------- ...
随机推荐
- 设置ListView的item多选
一,首先定义一个类来关联Adapter和Activity能够记住点击的位置 public class MyViewHoler{ public CheckBox cb; public TextView ...
- JQuery 拖动层
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
- 用友U8客户端连接不上服务器全攻略
用友U8客户端连接不上服务器全攻略 http://www.enet.com.cn2009年09月23日09:26 来自论坛 [导读]:如果网络不通,就让用户查找网络原因 检查步骤: 1.网络是否通? ...
- JS判断是否在微信浏览器打开
if (browser.versions.mobile) {//判断是否是移动设备打开.browser代码在下面 var ua = navigator.userAgent.toLowerCase(); ...
- jQuery学习-事件之绑定事件(一)
我们都知道jQuery的事件其思想来源于Dean Edwards的addEvent,通过源码我们知道jQuery在为元素绑定事件时,每种类型的事件(click,blur)时只绑定了一次对应类型的事件处 ...
- DTU软硬件方案
经过周末的思考以及已有的经验,准备将DTU研发项目命名为QN100,确定了初步的软硬件方案,产品名称大家如果有好的名字欢迎提供. 硬件: 采用STM32F101RD为主处理器, ...
- 论山寨手机与Android联姻的技术基础 【序】
山寨手机的兴起,离不开 MTK(联发科).MTK为手机制造提供了一揽子解决方案,其中既包括硬件,也包括软件.软件方面最重要的,是操作系统.MTK方案的软件的稳定性非常高,一方面是因为其硬件系统变化不大 ...
- POJ——放苹果
4:放苹果 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB 描述 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示) ...
- iterm快捷键及操作技巧(附Linux快捷键)
标签操作 新建标签:command + t 关闭标签:command + w 切换标签:command + 数字 command + 左右方向键 切换全屏:command + enter 查找:com ...
- Oracle检查与安装操作内容
Oracle 安装: 检查安装包 rpm -q binutils compat-libstdc++ elfutils-libelf elfutils-libelf-devel elfutils-lib ...