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

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

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

相关文章
|
1月前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
53 1
|
1月前
|
安全 编译器 C++
【C++篇】C++类与对象深度解析(三):类的默认成员函数详解
【C++篇】C++类与对象深度解析(三):类的默认成员函数详解
20 3
|
1月前
|
存储 编译器 C++
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作(二)
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作
|
1月前
|
存储 编译器 C++
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作(三)
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作
|
1月前
|
存储 编译器 C++
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作(一)
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作
|
5月前
|
编译器 C++ 存储
【C++语言】类和对象--默认成员函数 (中)
【C++语言】类和对象--默认成员函数 (中)
【C++语言】类和对象--默认成员函数 (中)
|
4月前
|
存储 编译器 C语言
【C++】string类的使用①(默认成员函数
本文介绍了C++ STL中的`string`类,它是用于方便地操作和管理字符串的类,替代了C语言中不便的字符数组操作。`string`基于`basic_string`模板,提供类似容器的接口,但针对字符串特性进行了优化。学习资源推荐[cplusplus.com](https://cplusplus.com/)。`string`类提供了多种构造函数,如无参构造、拷贝构造、字符填充构造等,以及析构函数和赋值运算符重载。示例代码展示了不同构造函数和赋值运算符的用法。
|
5月前
|
编译器 C++
【C++】类和对象④(类的默认成员函数:取地址及const取地址重载 )
本文探讨了C++中类的成员函数,特别是取地址及const取地址操作符重载,通常无需重载,但展示了如何自定义以适应特定需求。接着讨论了构造函数的重要性,尤其是使用初始化列表来高效地初始化类的成员,包括对象成员、引用和const成员。初始化列表确保在对象创建时正确赋值,并遵循特定的执行顺序。
|
5月前
|
编译器 C++
【C++】类和对象③(类的默认成员函数:赋值运算符重载)
在C++中,运算符重载允许为用户定义的类型扩展运算符功能,但不能创建新运算符如`operator@`。重载的运算符必须至少有一个类类型参数,且不能改变内置类型运算符的含义。`.*::sizeof?`不可重载。赋值运算符`=`通常作为成员函数重载,确保封装性,如`Date`类的`operator==`。赋值运算符应返回引用并检查自我赋值。当未显式重载时,编译器提供默认实现,但这可能不足以处理资源管理。拷贝构造和赋值运算符在对象复制中有不同用途,需根据类需求定制实现。正确实现它们对避免数据错误和内存问题至关重要。接下来将探讨更多操作符重载和默认成员函数。
|
5月前
|
存储 编译器 C++
【C++】类和对象③(类的默认成员函数:拷贝构造函数)
本文探讨了C++中拷贝构造函数和赋值运算符重载的重要性。拷贝构造函数用于创建与已有对象相同的新对象,尤其在类涉及资源管理时需谨慎处理,以防止浅拷贝导致的问题。默认拷贝构造函数进行字节级复制,可能导致资源重复释放。例子展示了未正确实现拷贝构造函数时可能导致的无限递归。此外,文章提到了拷贝构造函数的常见应用场景,如函数参数、返回值和对象初始化,并指出类对象在赋值或作为函数参数时会隐式调用拷贝构造。