Effective C++:条款33:避免遮掩继承而来的名称
(一)
以下这段代码:
int x;
void someFunc()
{
double x; //local variable
std::cin>>x; //read a new value to local x
}
这个指涉的是local变量x。而不是global变量x。由于内存作用域会的名称遮掩外围作用域的名称。
当编译器处于someFunc的作用域内并遭遇名称x时,他在local作用域内查找是否有什么东西带着这个名称。假设找到就不再找其它作用域。someFunc的x是double类型而global的x是int类型,并不要紧。C++的名称遮掩规则(name-hiding rules)所做的唯一事情就是:遮掩名称。
至于名称是否是同样或不同的类型,并不重要。
(二)
derived class继承声明于base class内的全部东西。derived class作用域被嵌套在base class作用域内:
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();
};
如果derived class内的mf4的实现像这样:
void Derived::mf4() {
mf2();
}
当编译器看到这里使用名称mf2,必须估算它指涉什么东西。查找各作用域。看看有没有某个名为mf2声明式。
首先查找local作用域(也就是mf4覆盖的作用域),没找到不论什么东西名为mf2.于是查找其外围作用域,class Derived覆盖的作用域。还是没找到不论什么东西名为mf2.于是再往外围移动,本例为base
class。
在那找到一个名为mf2的东西了。于是停止查找。假设Base还是没有mf2,查找便继续下去。首先找内含Base 的那个namespace的作用域,最后往global作用域找去。
(三)
这次我们重载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
class内全部名为mf1和mf3的函数都被derived class内的mf1和mf3函数遮掩掉了!
Derived d;
int x;
d.mf1();
d.mf1(x);//错误,Derived::mf1遮掩了Base::mf1
d.mf2();
d.mf3();
d.mf3(x);//错误,Derived::mf3遮掩了Base::mf3
即使base
class和derived classes内的函数有不同的參数类型也适用。并且不论函数是virtual或non-virtual也适用。
(四)解决上面的问题的方法!
能够用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声明式。否则某些你希望继承的名称会被覆盖。
(五)
有时候我们并不希望继承base
class的全部函数,这个时候就不能用public方式继承了,由于这违反了"base与derived classes之间的is-a关系!所以这个时候就要用private的继承方式了!
假设Derived唯一想继承的是base
class中的那个无參数版本号的mf1。
using在这里派不上用场。using会令继承而来的某给定名称之全部同名函数在Derived class中都可见(在这里假设用using的话,那么在base class中的全部mf1在derived class中都可见!)。
所以在这样的情况下,我们须要一个简单的转交函数(forwarding function):
class Base {
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int);
virtual void mf2();
void mf3();
void mf3(double);
}; class Derived : private Base {
public:
virtual void mf1()//转交函数
{
Base::mf1();//暗自转成inline
}
}; Derived d;
int x;
d.mf1();//调用的是Derived::mf1
d.mf1(x);//错误,Base::mf1()被遮掩了
请记住:
(1) derived
class内的名称会遮掩base classes内的名称。在public继承下没有人希望如此。
(2) 为了让遮掩的名称再见天日,可使用using声明式或转交函数(forwarding functions)。
Effective C++:条款33:避免遮掩继承而来的名称的更多相关文章
- Effective C++ Item 33 避免遮掩继承过来的名称
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie ? 不懂 c++为什么derived classes 内的名称要遮掩 base classe ...
- Effective C++ 33 避免遮掩继承而来的名称
首先介绍一个原则LSP(Liskov Substitution Principle),如果Class D以Public方式继承Class B,则所有B对象可以派上用场的任何地方,D对象一样可以派上用场 ...
- Effective C++ -----条款33:避免遮掩继承而来的名称
derived classes内的名称会遮掩base classes内的名称.在public继承下从来没有人希望如此. 为了让被遮掩的名称再见天日,可使用using声明式或转交函数(forwardin ...
- 条款33:避免遮掩继承而来的名称(Avoiding hiding inherited names)
NOTE: 1.derived classes 内的名称会遮掩base classes内的名称.在public继承下从来没有人希望如此. 2.为了让被遮掩的名称再见天日,可使用using 声明方式或转 ...
- [Effective C++ --033]避免遮掩继承而来的名称
这一章一直在想怎么写,因为比较基础,很容易理解,就按照需要来写吧. 假设我们有这样一个类: class Base { private: int x; public: ; virtual void mf ...
- 读书笔记_Effective_C++_条款三十三:避免遮掩继承而来的名称
名称的遮掩可以分成变量的遮掩与函数的遮掩两类,本质都是名字的查找方式导致的,当编译器要去查找一个名字时,它一旦找到一个相符的名字,就不会再往下去找了,因此遮掩本质上是优先查找哪个名字的问题. 而查找是 ...
- effective C++ Item 33 避免隐藏继承而来的名字
1. 普通作用域中的隐藏 名字实际上和继承没有关系.有关系的是作用域.我们都知道像下面的代码: int x; // global variable void someFunc() { double x ...
- 读书笔记 effective C++ Item 33 避免隐藏继承而来的名字
1. 普通作用域中的隐藏 名字实际上和继承没有关系.有关系的是作用域.我们都知道像下面的代码: int x; // global variable void someFunc() { double x ...
- [EffectiveC++]item33:避免遮掩继承而来的名称。
先看看: ZT C++ 重载.覆盖和隐藏的区别 http://www.cnblogs.com/jeanschen/p/3405987.html 隐藏是指派生类的函数屏蔽了与其同名的基类函数,规则如下: ...
随机推荐
- 一个常见下拉菜单的样式:一体化小三角(纯css手写解决)
类似下拉菜单2个一体化小三角,习惯上用字体图标加jQuery处理,比较方便,但是下面纯css手写解决方式,效果也还不错,对CSS知识也是一个比较好的孔固. 小三角用了2种不同处理方式:1.利用bord ...
- Oracle基础重点概要
表空间 逻辑上处于数据库之下,利用表空间可以更灵活地规划数据库结构. 创 ...
- (转)Unity中武器与人物的碰撞检测
自:http://blog.csdn.net/Monzart7an/article/details/24435843 目前来说有三种思路,其实前两种算变种了: 1.动画关键帧回调 + 范围检测. 这个 ...
- linux下mysql-5.5.15安装详细步骤
linux下mysql-5.5.15安装详细步骤 注:该文档中用到的目录路径以及一些实际的值都是作为例子来用,具体的目录路径以各自安装时的环境为准 mysql运行时需要一个启动目录.一个安装目录和一个 ...
- youtube相关
Ubuntu环境巧妙下载YouTube视频 http://www.linuxidc.com/Linux/2008-07/14555.htm 今天,我就为大家介绍在Ubuntu环境总一个专门从 YouT ...
- HBase数据迁移至Hive
背景:需要将HBase中表xyz(列簇cf1,列val)迁移至Hive 1. 建立Hive和HBase的映射关系 1.1 运行hive shell进入hive命令行模式,运行如下脚本 CREA ...
- DOM与JavaScript、jQuery之间的关系
DOM(document object model) 其实是浏览器内元素对象的一个总称 我们用JavaScript对网页进行的所有操作都是通过DOM进行的.DOM属于浏览器,而不是JavaScript ...
- Java从零开始学三十一(DATE和Calendar类)
一.Date类 Date类是一个相对较为简单的操作类,在使用中直接使用java.util.Date类的构造方法并进行输出就可以得到一个完整的日期 二.Calendar类 Calendar类可以将取得的 ...
- 算法笔记_189:历届试题 横向打印二叉树(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 二叉树可以用于排序.其原理很简单:对于一个排序二叉树添加新节点时,先与根节点比较,若小则交给左子树继续处理,否则交给右子树. 当遇到空子树 ...
- MySQL 联合索引测试2
接上一篇文章: http://www.cnblogs.com/xiaoit/p/4430300.html 1:首先删掉上一篇建立的索引,重新建立一个. mysql> DROP INDEX idx ...