Effective C++ 读书笔记 Item33 避免隐藏继承来的名称(继承与作用域嵌套) 朱雀 2020-07-05 02:33 700阅读 0赞 其实本文的话题和继承完全没有关系,隐藏名称是作用域的问题。 在C++中每一对`{` `}`都会开启一个新的作用域,并嵌套在当前作用域中。 # 一个示例 # int x; void func(){ double x; cin>>x; // read a new value for local x } > 可以看到`double x`隐藏了`int x`,因为C++的名称隐藏规则(name-hiding rules)隐藏的是名称,和类型无关! # 继承作用域 # 子类可以访问父类中的名称,是因为子类的作用域是嵌套(nested in)在父类的作用域中的。 这一点也很符合直觉: class Base{ public: void func_base(); }; class Derived{ public: void func_derived(){ func_base(); } }; 在func\_derived()中调用func\_base()时,编译器首先检查当前作用域内是否有名称func\_base(当然C++是不允许在函数里定义函数的), 没有找到;然后去父作用域Derived中寻找名称func\_base,仍然未找到;然后去再上一级作用域Base中寻找func\_base,找到了!然后调用Base::func\_base()。 > 如果还没找到,编译器还会去Derived所在命名空间下、全局作用域下寻找。 # 隐藏父类的名称 # 子类中重写(override)与父类方法同名的方法,将会隐藏父类中所有同名的重载方法。例如: class Base{ public: virtual void func()=0; void func(int); }; class Derived: public Base{ public: virtual void func(); }; ... Derived d; d.func(1); // Error! `Derived`中声明的`func`方法,隐藏了父类中所有的`func`名称,包括所有的重载函数。 # 继承所有重载方法 # 当你从父类继承来了一系列的重载(overload)方法,而只想重写(override)其中的一个时,可以用`using`,否则其他重载方法会被隐藏。 class Derived: public Base{ public: using Base::func; virtual void func(); }; ... d.func(1); // OK # 继承一个重载方法 # 在public继承中,子类和父类是"is-a"的关系(见Item 32),所以通常我们希望从父类继承所有的方法。 但如果是private继承(见Item 39), 可能你只想要其中的一个,这时可以定义一个转发函数(forwarding function): class Base{ public: virtual void mf1() = 0; virtual void mf1(int); }; class Derived: private Base{ public: virtual void f1(){ Base::mf1(); // 这是一个inline函数,见 Item30 } }; # 总结 # * 子类中的名称会隐藏父类中所有同名的属性。public继承表示这"is-a"的关系,应该避免这样做。 * 使用`using`声明或者转发函数可以使父类名称再次可见。
还没有评论,来说两句吧...