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

368次阅读  |  发布于2年以前

学习面向对象的语言,了解继承是必不可少的。您可能觉得这太基础了,大家可都是老“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语法。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8