查看原文
其他

C++ Trick:小心,子类隐藏父类成员函数

果冻虾仁 编程往事 2022-08-22

学习面向对象的语言,了解继承是必不可少的。您可能觉得这太基础了,大家可都是老“996”了,还用介绍封装、继承、多态那老三样吗?


😌哎,您别着急。本文讲的是一个C++语言的小Trick,您或许了解也或许不了解,各位看官请细听分说。


按常理来说,如果父类的成员函数是public的,那么子类应该也能直接调用父类定义的函数,所谓的“继承”也便是这个含义。口说无凭,手上见真章,说有这么两个类,它这样,这样,这样……


啪啪啪,你甩给我一段代码:

#include <iostream>#include <string>using namespace std;class Staff {public: void set_birth(string birth) { _birth = birth; }
private: string _birth;};
class Leader:public Staff {};
int main() { Leader s; s.set_birth("1990/10/10"); return 0;}


这段代码没问题,编译也能过。父类有个成员函数set_birth,接收一个string类型,设置生日。比如"1990/10/10"。子类以直接调用set_birth。


“这有什么值得一说的?”夺门而出我连忙追上去让你把门还我。


您接着瞧,如果子类现在需要实现一个传入int类型的set_birth呢?

class Leader:public Staff {public: void set_birth(int birth) { set_birth(to_string(birth)); }};
int main() { Leader s; s.set_birth(19901010); return 0;}


类set_birth(int)内调用了父类的set_birth(string)。看着没问题,但是编译却报错了:

demo.cpp:17:19: error: no viable conversion from 'std::__1::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') to 'int'
        set_birth(to_string(birth));
                  ^~~~~~~~~~~~~~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/string:875:5: note: candidate function
    operator __self_view() const _NOEXCEPT { return __self_view(data(), size()); }
    ^
demo.cpp:16:24: note: passing argument to parameter 'birth' here
    void set_birth(int birth) 
{
                       ^
1 error generated.


编译器编译子类时似乎不能识别set_birth(string)。我们再测试一下是不是真的不能识别:

class Leader:public Staff {public: void set_birth(int birth) { }};
int main() { Leader s; s.set_birth("19901010"); return 0;}


这样编译,也报错:

demo.cpp:22:17: error: cannot initialize a parameter of type 'int' with an lvalue of type 'const char [9]'
    s.set_birth("19901010");
                ^~~~~~~~~~
demo.cpp:16:24: note: passing argument to parameter 'birth' here
    void set_birth(int birth) 
{
                       ^
1 error generated.


果然,子类已经无法调用父类的public成员函数了。明明刚才还可以,怎么set_birth(string)对子类突然不可见了呢?


奥秘在于,子类重载了父类的同名函数。此时父类的函数确实对子类是不可见的……


这其实不是一个复杂的知识点,只是容易让人稍不留意就遗忘。


解决方案是什么呢?其实也不难,想办法让父类的同名函数对子类可见!

class Leader:public Staff {public: using Staff::set_birth; void set_birth(int birth) { set_birth(to_string(birth)); }};
int main() { Leader s; s.set_birth(19901010); return 0;}


一行using就可以搞定!


using Staff::set_birth;


注意这不是C++11!这是C++11之前就有的using语法。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存