C++ 重载、隐藏、覆盖的区别小结 结合这C 代码深入理解重载Overload、隐藏Hide和覆盖Override也叫重写这三个核心概念用这段代码作为核心案例由浅入深地拆解它们的区别和本质。一、先明确三个概念的核心定义这三个概念都是 C 中函数名复用的场景但适用范围、规则和目的完全不同先看一张对比表建立整体认知概念中文名称适用范围核心特征本质目的Overload重载同一个作用域内函数名相同参数列表个数/类型/顺序不同返回值不影响方便同一功能的不同参数调用Override覆盖/重写子类与父类之间子类重写父类的虚函数函数签名名参数const完全一致实现多态运行时动态绑定Hide隐藏/遮蔽子类与父类之间子类函数名覆盖父类同名函数无论参数/虚函数与否编译期静态屏蔽作用域优先原则导致的“遮蔽”覆盖是特殊的隐藏。二、结合代码逐个拆解逐个分析这三个概念并用扩展代码演示效果。1. 重载Overload—— 同一作用域内的“同名不同参”核心规则必须在同一个类/同一个作用域中函数名完全相同参数列表必须不同个数、类型、顺序三者至少一个不同返回值、是否是虚函数不影响重载但仅返回值不同不算重载。代码中的重载案例在Base类中两个show函数就是典型的重载1234567891011classBase{public:Base(inta):ma(a) {}// 重载1无参 showvirtualvoidshow() {coutBase::show()endl;}// 重载2带int参数的 show —— 与上面构成重载virtualvoidshow(inti) {coutBase::show(int)endl;}private:intma;};它们在Base这个同一作用域内函数名都是show参数列表不同一个无参一个int参数都是虚函数但即使不是虚函数依然是重载。重载的调用示例123456intmain() {Base b(10);b.show();// 调用 Base::show() —— 匹配无参版本b.show(5);// 调用 Base::show(int) —— 匹配int参数版本return0;}编译期编译器会根据实参类型自动匹配对应的重载函数这是静态绑定编译期确定调用哪个。2. 覆盖/重写Override—— 子类对父类虚函数的“精准替换”核心规则必须在子类与父类之间父类函数必须是虚函数virtual子类函数的函数签名完全一致函数名 参数列表 const/volatile 属性完全相同子类函数可以加override关键字显式声明C11 后推荐编译器会检查是否真的覆盖。代码中的覆盖案例Derive类中的show()覆盖了Base类中的无参show()123456789classDerive :publicBase{public:Derive(inta,intb):Base(a), mb(b) {}// 覆盖与 Base::show() 签名完全一致且父类是虚函数voidshow() override {coutDerive::show()endl;}// 加override更规范private:intmb;};父类Base::show()是虚函数子类Derive::show()函数名、参数列表无参完全一致这就是“覆盖”目的是实现多态。覆盖的多态调用示例123456intmain() {Base* ptr newDerive(1, 2);// 父类指针指向子类对象ptr-show();// 调用 Derive::show() —— 运行时动态绑定多态deleteptr;return0;}输出Derive::show()这里因为覆盖了虚函数运行时会根据对象的实际类型Derive调用对应的函数而不是指针类型Base这是动态绑定。3. 隐藏/遮蔽Hide—— 子类对父类同名函数的“编译期屏蔽”核心规则必须在子类与父类之间子类定义了与父类同名的函数无论参数是否相同、是否是虚函数编译器在编译子类作用域时会屏蔽父类所有同名函数即使父类是重载/虚函数这是编译期静态行为与多态无关。代码中的隐藏案例重点你的代码中Derive类定义了show()会隐藏父类Base中所有名为show的函数包括show()和show(int)123456intmain() {Derive d(1, 2);d.show();// 正常调用 Derive::show()// d.show(5); // 编译错误父类的 show(int) 被隐藏了return0;}为什么会报错因为子类Derive中有show()函数编译器在解析d.show(5)时会优先在Derive作用域找show发现只有无参的show()没有show(int)且不会去父类找被隐藏了因此编译失败。隐藏的其他场景补充理解即使子类函数参数与父类不同依然会隐藏12345678910111213141516classDerive :publicBase{public:Derive(inta,intb):Base(a), mb(b) {}// 子类定义 show(double) —— 与父类 show(int) 不同参但依然隐藏父类所有 showvoidshow(doubled) {coutDerive::show(double)endl;}private:intmb;};intmain() {Derive d(1,2);// d.show(5); // 编译错误父类 show(int) 被隐藏子类只有 show(double)d.show(5.0);// 正常调用 Derive::show(double)return0;}如何解除隐藏如果想在子类中调用父类被隐藏的函数有两种方式用using声明把父类函数引入子类作用域1234567891011121314151617classDerive :publicBase{public:usingBase::show;// 解除父类所有 show 函数的隐藏Derive(inta,intb):Base(a), mb(b) {}voidshow() override {coutDerive::show()endl;}private:intmb;};// 此时调用正常intmain() {Derive d(1,2);d.show();// 调用 Derive::show()d.show(5);// 调用 Base::show(int) —— 隐藏被解除return0;}显式指定父类作用域调用12345intmain() {Derive d(1,2);d.Base::show(5);// 直接调用父类的 show(int)不受隐藏影响return0;}三、容易混淆的点对比1. 覆盖 vs 重载维度覆盖Override重载Overload作用域跨类父类→子类同作用域同一类函数签名必须完全一致必须不同参数列表虚函数要求父类必须是虚函数无要求可虚可非虚绑定方式运行时动态绑定编译期静态绑定2. 覆盖 vs 隐藏维度覆盖Override隐藏Hide前提父类是虚函数 签名一致只要子类有同名函数无论参数/虚函数本质多态的实现方式作用域优先导致的屏蔽绑定方式运行时动态绑定编译期静态屏蔽父类函数可用性父类虚函数被“替换”但可通过作用域调用父类同名函数被屏蔽需显式调用四、完整演示代码把上述所有场景整合可以直接运行测试12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849#include iostreamusingnamespacestd;classBase{public:Base(inta):ma(a) {}// 重载1无参虚函数virtualvoidshow() {coutBase::show()endl;}// 重载2带int参数的虚函数与上面构成重载virtualvoidshow(inti) {coutBase::show(int) iendl;}private:intma;};classDerive :publicBase{public:usingBase::show;// 解除父类show的隐藏注释掉这行看隐藏效果Derive(inta,intb):Base(a), mb(b) {}// 覆盖重写父类无参showvoidshow() override {coutDerive::show()endl;}// 新增子类独有的show(double)会隐藏父类show除非加usingvoidshow(doubled) {coutDerive::show(double) dendl;}private:intmb;};intmain() {// 1. 测试Base的重载Base b(10);b.show();// Base::show()b.show(5);// Base::show(int) 5// 2. 测试多态覆盖Base* ptr newDerive(1, 2);ptr-show();// Derive::show() —— 动态绑定ptr-show(6);// Base::show(int) 6 —— 子类未覆盖该版本调用父类deleteptr;// 3. 测试子类的隐藏与解除Derive d(1, 2);d.show();// Derive::show()d.show(7);// Base::show(int) 7加using后生效否则编译错误d.show(3.14);// Derive::show(double) 3.14d.Base::show();// 显式调用父类show()return0;}总结重载是同一作用域内“同名不同参”编译期静态匹配目的是简化调用覆盖是子类重写父类虚函数签名一致运行时动态绑定是多态的核心隐藏是子类同名函数屏蔽父类所有同名函数编译期行为需用using或作用域显式调用父类函数。这三个概念的核心区别在于作用域和绑定时机重载是“同作用域编译期”覆盖是“跨类运行期”隐藏是“跨类编译期屏蔽”。补充12345678910111213141516171819202122#include iostreamusingnamespacestd;classBase// Base base(10);{public:Base(inta):ma(a) {}// 虚函数virtualvoidshow() {coutBase::show()endl;}virtualvoidshow(inti) {coutBase::show(int)endl;}private:intma;};classDerive :publicBase{public:Derive(inta,intb):Base(a), mb(b) {}voidshow() {coutDerive::showendl;}private:intmb;};补充说明虚函数与重写Base类中定义了两个虚函数show()和show(int i)。Derive类重写了无参版本show()但没有重写带参版本show(int i)。由于 C 的名称隐藏规则Derive类中定义的show()会隐藏掉基类中所有名为show的函数包括show(int i)。典型调用行为123456intmain() {Derive d(1, 2);d.show();// 正确调用 Derive::show()// d.show(10); // 编译错误基类的 show(int) 被隐藏了return0;}如果想在Derive中也能调用Base::show(int)需要在Derive中添加using Base::show;来解除名称隐藏。到此这篇关于C 重载、隐藏、覆盖的区别小结的文章就介绍到这了