Effective C++ 读书笔记 Item33 避免隐藏继承来的名称(继承与作用域嵌套)

朱雀 2020-07-05 02:33 812阅读 0赞

其实本文的话题和继承完全没有关系,隐藏名称是作用域的问题。 在C++中每一对{ }都会开启一个新的作用域,并嵌套在当前作用域中。

一个示例

  1. int x;
  2. void func(){
  3. double x;
  4. cin>>x; // read a new value for local x
  5. }

可以看到double x隐藏了int x,因为C++的名称隐藏规则(name-hiding rules)隐藏的是名称,和类型无关!

继承作用域

子类可以访问父类中的名称,是因为子类的作用域是嵌套(nested in)在父类的作用域中的。 这一点也很符合直觉:

  1. class Base{
  2. public:
  3. void func_base();
  4. };
  5. class Derived{
  6. public:
  7. void func_derived(){
  8. func_base();
  9. }
  10. };

在func_derived()中调用func_base()时,编译器首先检查当前作用域内是否有名称func_base(当然C++是不允许在函数里定义函数的), 没有找到;然后去父作用域Derived中寻找名称func_base,仍然未找到;然后去再上一级作用域Base中寻找func_base,找到了!然后调用Base::func_base()。

如果还没找到,编译器还会去Derived所在命名空间下、全局作用域下寻找。

隐藏父类的名称

子类中重写(override)与父类方法同名的方法,将会隐藏父类中所有同名的重载方法。例如:

  1. class Base{
  2. public:
  3. virtual void func()=0;
  4. void func(int);
  5. };
  6. class Derived: public Base{
  7. public:
  8. virtual void func();
  9. };
  10. ...
  11. Derived d;
  12. d.func(1); // Error!

Derived中声明的func方法,隐藏了父类中所有的func名称,包括所有的重载函数。

继承所有重载方法

当你从父类继承来了一系列的重载(overload)方法,而只想重写(override)其中的一个时,可以用using,否则其他重载方法会被隐藏。

  1. class Derived: public Base{
  2. public:
  3. using Base::func;
  4. virtual void func();
  5. };
  6. ...
  7. d.func(1); // OK

继承一个重载方法

在public继承中,子类和父类是”is-a”的关系(见Item 32),所以通常我们希望从父类继承所有的方法。 但如果是private继承(见Item 39), 可能你只想要其中的一个,这时可以定义一个转发函数(forwarding function):

  1. class Base{
  2. public:
  3. virtual void mf1() = 0;
  4. virtual void mf1(int);
  5. };
  6. class Derived: private Base{
  7. public:
  8. virtual void f1(){
  9. Base::mf1(); // 这是一个inline函数,见 Item30
  10. }
  11. };

总结

  • 子类中的名称会隐藏父类中所有同名的属性。public继承表示这”is-a”的关系,应该避免这样做。
  • 使用using声明或者转发函数可以使父类名称再次可见。

发表评论

表情:
评论列表 (有 0 条评论,812人围观)

还没有评论,来说两句吧...

相关阅读