条款33:避免隐藏继承而来的名称

• 此例中混合了纯虚函数、虚函数、非虚函数等,只是为了强调隐藏的是继承而来的名字,至于名字代表的是什么并不重要,即使enum、nested class、typedef也不例外。

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 class Base
 6 {
 7 public:
 8     virtual void mf1() = 0;
 9     virtual void mf1(int);
10     virtual void mf2();
11     void mf3();
12     void mf3(double);
13
14 private:
15     int x;
16 };
17
18 class Derived : public Base
19 {
20 public:
21     virtual void mf1();
22     void mf3();
23     void mf4();
24 };
25 int main()
26 {
27     Derived d;
28     int x;
29     d.mf1();    // 正确:调用Derived::mf1
30     d.mf1(x);   // 错误:因为Derived::mf1隐藏了Base::mf1
31     d.mf2();    // 正确:调用Base::mf2
32     d.mf3();    // 正确:调用Derived::mf3
33     d.mf3(x);   // 错误:因为Derived::mf3隐藏了Base::mf3
34
35     return 0;
36 }

说明:Base类中的任何同名函数都会被Derived类中同名函数隐藏掉,不论函数是否为虚函数,这些机制的是为了防止从基类中继承重载函数。实际上如果你使用public继承而又不继承基类中的重载函数,那就违反了is-a关系。

• 如果确实想使用基类Base中同名的函数,那么就需要使用using Base::名字

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 class Base
 6 {
 7 public:
 8     virtual void mf1() = 0;
 9     virtual void mf1(int);
10     virtual void mf2();
11     void mf3();
12     void mf3(double);
13
14 private:
15     int x;
16 };
17
18 class Derived : public Base
19 {
20 public:
21     using Base::mf1;    // 让Base类中名为mf1和mf3的所有东西在
22     using Base::mf3;    // 派生类Derived中可见
23     virtual void mf1();
24     void mf3();
25     void mf4();
26 };
27
28 int main()
29 {
30     Derived d;
31     int x;
32     d.mf1();    // 正确:调用Derived::mf1
33     d.mf1(x);   // 正确:调用Base::mf1(int)
34     d.mf2();    // 正确:调用Base::mf2
35     d.mf3();    // 正确:调用Derived::mf3
36     d.mf3(x);   // 正确:调用Base::mf3(double)
37
38     return 0;
39 }

• 在public继承下,不想继承Base中的所有函数是不可能的。考虑private继承下的一个例子:Derived以private方式继承Base,其想唯一继承的是mf1的无参版本,如果使用using,那么重载版本也会被继承。以下描述了一个简单的转交函数(forwarding function):

 1 #include <iostream>
 2
 3 using namespace std;
 4
 5 class Base
 6 {
 7 public:
 8     virtual void mf1() = 0;
 9     virtual void mf1(int);
10     virtual void mf2();
11     void mf3();
12     void mf3(double);
13
14 private:
15     int x;
16 };
17
18 class Derived : private Base
19 {
20 public:
21     virtual void mf1()  // forwarding function
22     {
23         Base::mf1();
24     }
25     void mf3();
26     void mf4();
27 };
28
29 int main()
30 {
31     Derived d;
32     int x;
33     d.mf1();    // 正确:调用Derived::mf1
34
35     return 0;
36 }

总结:Derived中的名称会隐藏Base中的名称,不论是什么类型,而使用using声明或者转交函数可以解决这个问题。

时间: 2024-10-04 15:09:53

条款33:避免隐藏继承而来的名称的相关文章

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 voi

《Effective C++》学习笔记——条款33

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************** 六.继承与面向对象设计 Inheritance and Object-Oriented Design 条款33 : 避免遮掩继承而来的名称 rule 33 : Avoid hiding inherited names 1.关于名称,无关于继承,而关于和作用域有关

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++》之条款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

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

条款36: 区分接口继承和实现继承

作为类的设计者,有时希望派生类只继承成员函数的接口(声明):有时希望派生类同时继承函数的接口和实现,但允许派生类改写实现:有时则希望同时继承接口和实现,并且不允许派生类改写任何东西. class Shape { public: virtual void draw() const = 0; virtual void error(const string& msg); int objectID() const; ... }; class Rectangle: public Shape { ... }

条款33: 明智地使用内联

调用函数实际上将程序执行顺序转移到函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方.这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后先要恢复现场,并按原来保存地址继续执行. 当程序运行到某个节点时,如果发现有函数调用语句(函数要事先声明或者事先定义),程序就自动保存当前程序运行的各个参数.变量到堆栈中去,然后利用所给函数参数调用该函数并运行得出结果,并且将结果保存到内存寄存器中,然后程序自动返回函数调用前的节点处,再将堆栈中的数据出栈,然后再继续运行

避免遮掩继承而来的名称

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

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

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