Effective C++ 33 避免遮掩继承而来的名称

  首先介绍一个原则LSP(Liskov Substitution Principle),如果Class D以Public方式继承Class B,则所有B对象可以派上用场的任何地方,D对象一样可以派上用场。

对于重载和重写,相信大家都已经有所了解。这里讨论一下在public继承的时候,重载函数的问题。

先看下面的例子:

 1 class Base
 2     {
 3     public:
 4         virtual void mf1() = 0;
 5         virtual void mf1(int);
 6         virtual void mf2();
 7         void mf3();
 8         void mf3(double);
 9         ...
10     private:
11         int x_;
12     };
13     class Derived:public Base
14     {
15     public:
16         virtual void mf1();
17         void mf3();
18         void mf4();
19         ...
20     };  

在基类中,mf1() 和mf3()都被重载,子类public继承父类,这里的子类覆盖了父类中所有名为mf1和mf3的函数。因而以下调用有些会失败。

Derived d;
int x;
...
d.mf1(); // Derived::mf1
d.mf1(x); //错误 Derived::mf1 hiden Base::mf1
d.mf2();  // Base::mf2
d.mf3();  // Derived::mf3
d.mf3(x); //错误Derived::mf3 hiden Base::mf3

由此可见,及时子类和父类内的函数有不同的参数时,子类的函数还是会覆盖所有父类中同名的函数。

这样做的原因:避免从疏远的父类中继承重载函数。但是实际上,public继承应该遵循LSP原则,即父类和子类是Is-a 的关系,所以我们可以通过using,显示地实现对父类同名重载函数的继承。

1 class Base{...}; //同上
2 class Derived:public Base{
3 public:
4     //让Base class内名为mf1与mf3的所有东西在
5      //Derived作用域内都可见(并且都是public)
6     using Base::mf1;
7     using Base::mf3;
8     ....//同上
9 };  
Derived d;
int x;
...
d.mf1(); //no problem. call Derived::mf1
d.mf1(x); //no problem. Base::mf1
d.mf2();  //no problem. call Base::mf2
d.mf3();  //no problem. call Derived::mf3
d.mf3(x); //no problem. Base::mf3  

如果你不想继承所有的重载函数,则你不应该使用public继承,因为这样会违反LSP原则,你可以使用private继承,为了选择性的继承重载函数,可以使用inline 转交函数(forwarding function),具体实现如下:

 1 class Base
 2 {
 3 public:
 4     virtual void mf1() = 0;
 5     virtual void mf1(int);
 6     ... //same as above
 7 };
 8 class Derived:private Base
 9 {
10 public:
11     virtual void mf1()//转交函数(forwarding function)
12     {
13         Base::mf1();
14     }
15     ...
16 };
17 ...
18 Derived d;
19 int x;
20 d.mf1(); //good! call Derived::mf1
21 d.mf1(x); //Error as suppose,Base::mf1() was hidden.  

关键:

  子类内的名称会遮掩父类内的名称,在pubilc继承下,不应该这样做。

  为了使被遮掩的名称可见,使用using声明或者转交函数。

时间: 2024-09-15 14:15:11

Effective C++ 33 避免遮掩继承而来的名称的相关文章

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类型而gl

Effective C++ Item 33 避免遮掩继承过来的名称

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie ? 不懂 c++为什么derived classes 内的名称要遮掩 base classes 内的名称. 经验:derived classes 内的名称会遮掩 base classes 内的名称.在 public 继承下从来没有人希望如此. C++ 的名称遮掩规则所做的唯一事情就是: 遮掩名称 derived class 作用域被嵌套在 base class 作用域里 class Bas

《Effective C++》之条款33:避免遮掩继承而来的名称

<Effective C++> 条款33:避免遮掩继承而来的名称 遮掩行为与作用域有关.例子如下: int x;//global变量 void someFun() {     double x;//local 变量     std::cin >> x;//读一个新值赋予local变量x } 这个读取数据的语句指涉的是local变量x,而不是global变量x,因为内层作用域的名称会遮掩外围作用域的名称. 例如: class Base { private:     int x; pu

避免遮掩继承而来的名称

C++中类与类之间存在着两种名称遮盖关系,变量遮盖.函数遮盖.其本质都是名字的查找方式导致的,当编译器要找一个名字,它一旦找到一个相符的名字,就不会往下找了,因此遮掩本质上是优先查找那个名字的问题.     查找名字时,编译器先从子类开始,一旦找到了,就不再继续查找.无论普通函数,虚函数,还是纯虚函数,结果都是输出子类的函数调用. 避免遮掩继承而来的名称是因为,你在使用public继承而又不继承那些重载函数,就是违反base和derive class之间的 is 关系. 如果非要访问父类的方法,

条款33:避免遮掩继承而来的名称(Avoiding hiding inherited names)

NOTE: 1.derived classes 内的名称会遮掩base classes内的名称.在public继承下从来没有人希望如此. 2.为了让被遮掩的名称再见天日,可使用using 声明方式或转交函数(forwarding functions).

条款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(); ... }; 这个函数里面还有纯虚函数,虚函数以及非虚函数. 如果这里derived class调用了一个mf2函数的话,那么那么会先在de

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

关于OOP 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private,也可以是virtual或non-virtual. 2,成员函数的各个选项:virtual或non-virtual或pure-virtual. 3,成员函数和其他语言特性的交互影响:缺省参数值与virtual函数有什么交互影响?继承如何影响C++的名称查找规则?设计选项有如些?如果class的行为

effective c++条款32~40“继承与面向对象设计”整理

条款32:确定你的public继承塑模出is-a关系 以C++进行面向对象编程,最重要的一个规则是:public inheritance(公有继承)意味is-a(是一种)的关系. 在C++领域中,任何函数如果期望获得一个类型为基类的实参(而不管是传指针或是引用),都也愿意接受一个派生类对象(而不管是传指针或是引用).(只对public继承才成立.)好的接口可以防止无效的代码通过编译,因此你应该宁可采取"在编译期拒绝"的设计,而不是"运行期才侦测"的设计.is a并不

【C++常识】effective C++ 使用条款——内存管理/继承和面向对象设计/杂项

第六章 继承和面向对象设计 条款35: 使公有继承体现 "是一个" 的含义 1.子类对象一定"是一个"基类对象,基类对象不一定是子类对象 条款36: 区分接口继承和实现继承 1.希望派生类只继承成员函数的接口--将函数声明为纯虚函数 2.希望派生类同时继承函数的接口和实现,但允许派生类改写实现--将函数声明为虚函数 3.希望同时继承接口和实现,并且不允许派生类改写任何东西--声明为非虚函数 条款37: 决不要重新定义继承而来的非虚函数 1.基类声明为非虚的函数表示这