导读:本期聚焦于小伙伴创作的《C++中的覆盖(Override)与隐藏(Hiding)是什么?如何区分两者》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C++中的覆盖(Override)与隐藏(Hiding)是什么?如何区分两者》有用,将其分享出去将是对创作者最好的鼓励。

在C++的继承体系里,子类对父类成员的重新定义会分为覆盖和隐藏两种情况,两者的行为逻辑完全不同,很多开发者在使用继承时经常因为混淆两者导致程序运行结果不符合预期。下面先通过具体的代码示例来直观感受两者的差异。

什么是覆盖(Override)

覆盖是指子类重新定义父类中声明为virtual的虚函数,要求子类函数的函数名、参数列表、返回值类型都和父类虚函数完全一致,此时子类的函数会覆盖父类的虚函数实现,当通过父类指针或引用调用该函数时,会根据对象的实际类型动态调用子类的实现,也就是运行时多态的体现。

覆盖的代码示例

#include <iostream>
using namespace std;

// 父类
class Base {
public:
    // 声明为虚函数
    virtual void show() {
        cout << "Base show" << endl;
    }
    // 虚析构函数,保证删除子类对象时正确调用析构函数
    virtual ~Base() {}
};

// 子类
class Derived : public Base {
public:
    // 覆盖父类的show虚函数
    void show() override {  // override关键字是C++11引入的,用于显式标记覆盖,避免写错函数签名
        cout << "Derived show" << endl;
    }
};

int main() {
    Base* basePtr = new Derived();
    basePtr->show();  // 调用的是子类的show,输出Derived show
    delete basePtr;
    return 0;
}

什么是隐藏(Hiding)

隐藏指的是子类中定义了和父类同名的成员(可以是函数也可以是变量),此时子类的同名成员会遮蔽父类的同名成员,不管父类的成员是否为虚函数,只要名字相同就会触发隐藏。如果通过子类对象直接调用该成员,只会访问到子类的版本,父类的版本会被隐藏,除非显式指定父类作用域。

隐藏的代码示例

#include <iostream>
using namespace std;

class Base {
public:
    void print() {
        cout << "Base print" << endl;
    }
    // 重载的print函数,带参数
    void print(int num) {
        cout << "Base print num: " << num << endl;
    }
    int value = 10;
};

class Derived : public Base {
public:
    // 隐藏父类的print函数,即使参数不同也会隐藏所有父类同名函数
    void print() {
        cout << "Derived print" << endl;
    }
    int value = 20;
};

int main() {
    Derived d;
    d.print();  // 调用子类的print,输出Derived print
    // d.print(10);  // 编译错误,父类的带参print被隐藏了
    d.Base::print();  // 显式指定父类作用域,调用父类的无参print,输出Base print
    d.Base::print(10);  // 显式指定父类作用域,调用父类的带参print,输出Base print num: 10
    
    cout << d.value << endl;  // 输出子类的value,20
    cout << d.Base::value << endl;  // 显式指定父类作用域,输出父类的value,10
    return 0;
}

覆盖与隐藏的核心区别

我们可以从以下几个维度来区分覆盖和隐藏:

  • 触发条件不同:覆盖要求父类函数必须是虚函数,且子类函数的函数名、参数列表、返回值类型完全一致;隐藏只需要子类和父类的成员同名即可,和是否为虚函数、参数是否相同无关。
  • 调用逻辑不同:覆盖通过父类指针或引用调用时,会根据对象实际类型动态绑定到子类实现;隐藏无论通过什么方式调用,只要不显式指定父类作用域,都只会访问子类的版本。
  • 作用不同:覆盖是实现运行时多态的核心机制,用于让不同子类对同一行为有不同的实现;隐藏只是子类成员对父类同名成员的遮蔽,没有多态特性。

快速区分两者的方法

在实际开发中可以通过以下方式快速判断是覆盖还是隐藏:

  1. 先看父类的同名函数是否声明了virtual关键字,如果没有,那子类的定义一定是隐藏。
  2. 如果父类函数是虚函数,再看子类函数的函数名、参数列表、返回值是否和父类完全一致,若一致则为覆盖,否则为隐藏。
  3. 尝试通过父类指针指向子类对象,调用该成员,如果调用的是子类实现则是覆盖,否则是隐藏。

另外C++11引入了override关键字,在子类函数声明后加上该关键字,编译器会检查是否真的覆盖了父类的虚函数,如果没有覆盖会直接报错,能有效避免把覆盖写成隐藏的问题。

C++OverrideHiding多态虚函数修改时间:2026-06-09 13:33:47

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。