- C++
【C++11】final, override,重载,重写覆盖,重写隐藏
- 2025-8-11 13:15:49 @
2 条评论
-
admin SU @ 2025-8-11 13:18:18
【C++11】final, override,重载,重写覆盖,重写隐藏学习笔记教程
一、C++11新增关键字:final与override
在C++11标准中,引入了
final
和override
两个关键字,用于增强类继承和虚函数使用的安全性与可读性。1. final关键字
final
主要用于限制类的继承或虚函数的重写,有两种使用场景:-
修饰类:被
final
修饰的类不能被继承。class Base final { // Base类被final修饰,无法被继承 public: void func() {} }; // class Derived : public Base {}; // 编译错误,Base是final类
-
修饰虚函数:被
final
修饰的虚函数,派生类不能重写该函数。class Base { public: virtual void func() final {} // 虚函数被final修饰 }; class Derived : public Base { public: // void func() {} // 编译错误,无法重写final虚函数 };
2. override关键字
override
用于显式声明派生类中的函数是重写基类的虚函数,主要作用是检查重写的正确性(如函数名、参数列表、返回值是否与基类虚函数一致)。-
正确用法:
class Base { public: virtual void func(int x) {} // 基类虚函数 }; class Derived : public Base { public: void func(int x) override {} // 正确重写,编译通过 };
-
错误示例(参数不一致):
class Derived : public Base { public: // void func(double x) override {} // 编译错误,参数与基类不一致 };
-
错误示例(非虚函数重写):
class Base { public: void func() {} // 非虚函数 }; class Derived : public Base { public: // void func() override {} // 编译错误,基类中无对应虚函数 };
二、重载(Overload)
重载指同一作用域内,函数名相同但参数列表(参数类型、个数、顺序)不同的函数,与返回值类型无关。
特点:
- 函数名相同,参数列表不同;
- 必须在同一类中或同一作用域;
- 与是否为虚函数无关;
- 调用时根据参数自动匹配。
示例:
class Math { public: // 重载:参数个数不同 int add(int a, int b) { return a + b; } int add(int a, int b, int c) { return a + b + c; } // 重载:参数类型不同 double add(double a, double b) { return a + b; } // 重载:参数顺序不同 void print(int a, double b) { cout << a << " " << b << endl; } void print(double a, int b) { cout << a << " " << b << endl; } };
三、重写(覆盖,Override)
重写指派生类重新定义基类中虚函数的实现,要求函数名、参数列表、返回值完全一致(协变返回类型除外)。
特点:
- 基类函数必须是虚函数(用
virtual
修饰); - 派生类函数与基类函数函数名、参数列表、返回值完全一致;
- 派生类函数访问权限可以比基类更宽松(如基类
protected
,派生类public
); - 通过基类指针/引用调用时,会根据对象实际类型动态绑定(多态)。
示例:
class Animal { public: virtual void speak() { // 基类虚函数 cout << "动物叫" << endl; } }; class Dog : public Animal { public: void speak() override { // 重写基类虚函数 cout << "汪汪叫" << endl; } }; int main() { Animal* animal = new Dog(); animal->speak(); // 输出"汪汪叫",动态绑定 return 0; }
四、重写隐藏(名字隐藏,Name Hiding)
隐藏指派生类中的函数屏蔽了基类中同名函数(无论参数是否相同),导致基类函数在派生类中不可见。
产生场景:
- 派生类函数与基类非虚函数同名(无论参数是否相同);
- 派生类函数与基类虚函数同名但参数不同(此时不构成重写,而是隐藏)。
特点:
- 基类函数被派生类同名函数“隐藏”,无法直接通过派生类对象调用;
- 若要调用基类函数,需显式使用
基类名::函数名
; - 不涉及多态,调用时根据指针/引用的类型(静态类型)匹配。
示例1:非虚函数同名隐藏
class Base { public: void func(int x) { // 非虚函数 cout << "Base: " << x << endl; } }; class Derived : public Base { public: void func() { // 同名函数,隐藏基类func(int) cout << "Derived: no param" << endl; } }; int main() { Derived d; d.func(); // 正确,调用派生类func() // d.func(10); // 错误,基类func(int)被隐藏 d.Base::func(10); // 正确,显式调用基类函数 return 0; }
示例2:虚函数参数不同导致隐藏
class Base { public: virtual void func(int x) { // 虚函数 cout << "Base: " << x << endl; } }; class Derived : public Base { public: void func(double x) { // 参数不同,不构成重写,隐藏基类func(int) cout << "Derived: " << x << endl; } }; int main() { Base* b = new Derived(); b->func(10); // 调用基类func(int)(因派生类未重写,静态绑定) return 0; }
五、重载、重写、隐藏对比表
特性 重载(Overload) 重写(覆盖,Override) 隐藏(Name Hiding) 作用域 同一类/同一作用域 基类与派生类 函数关系 同名不同参 虚函数,同名同参同返回值 同名(参数可同可不同) 多态性 无(静态绑定) 有(动态绑定) 无(静态绑定) 调用依据 参数列表 对象实际类型 指针/引用的静态类型 关键字关联 无 可配合 override
检查无 基类函数调用 直接调用 通过基类指针/引用调用基类版本 需显式用 基类名::函数名
六、总结
final
限制继承或虚函数重写,override
显式声明重写并检查正确性,二者均用于增强代码安全性;- 重载是同一作用域的同名不同参函数,与继承无关;
- 重写是派生类重写基类虚函数(同名同参),支持多态;
- 隐藏是派生类同名函数屏蔽基类函数,需显式调用基类版本。
掌握这些概念有助于避免继承中的常见错误,写出更清晰、安全的C++代码。
-
-
2025-8-11 13:18:07@
重载、重写覆盖和重写隐藏的具体示例
一、重载(Overload)示例
重载是指在同一作用域内,函数名相同但参数列表不同的函数集合:
#include <iostream> using namespace std; class Calculator { public: // 1. 参数个数不同 int add(int a, int b) { cout << "两个int相加: "; return a + b; } int add(int a, int b, int c) { cout << "三个int相加: "; return a + b + c; } // 2. 参数类型不同 double add(double a, double b) { cout << "两个double相加: "; return a + b; } // 3. 参数顺序不同 void print(int num, const string& str) { cout << "int在前: " << num << " " << str << endl; } void print(const string& str, int num) { cout << "string在前: " << str << " " << num << endl; } }; int main() { Calculator calc; cout << calc.add(2, 3) << endl; // 调用add(int, int) cout << calc.add(2, 3, 4) << endl; // 调用add(int, int, int) cout << calc.add(2.5, 3.5) << endl; // 调用add(double, double) calc.print(10, "hello"); // 调用print(int, string) calc.print("world", 20); // 调用print(string, int) return 0; }
输出结果:
两个int相加: 5 三个int相加: 9 两个double相加: 6 int在前: 10 hello string在前: world 20
二、重写覆盖(Override)示例
重写覆盖是指派生类重新实现基类中的虚函数,函数签名完全一致:
#include <iostream> using namespace std; // 基类 class Shape { public: // 虚函数,可被重写 virtual void draw() { cout << "绘制基本图形" << endl; } virtual double area() { return 0.0; } }; // 派生类Circle class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} // 重写基类的draw函数 void draw() override { // 使用override明确表示重写 cout << "绘制圆形" << endl; } // 重写基类的area函数 double area() override { // 使用override明确表示重写 return 3.14159 * radius * radius; } }; // 派生类Rectangle class Rectangle : public Shape { private: double width, height; public: Rectangle(double w, double h) : width(w), height(h) {} // 重写基类的draw函数 void draw() override { cout << "绘制矩形" << endl; } // 重写基类的area函数 double area() override { return width * height; } }; int main() { Shape* shape1 = new Circle(5.0); Shape* shape2 = new Rectangle(4.0, 6.0); // 多态行为:调用实际对象类型的方法 shape1->draw(); // 输出"绘制圆形" cout << "面积: " << shape1->area() << endl; // 输出圆形面积 shape2->draw(); // 输出"绘制矩形" cout << "面积: " << shape2->area() << endl; // 输出矩形面积 delete shape1; delete shape2; return 0; }
输出结果:
绘制圆形 面积: 78.5397 绘制矩形 面积: 24
三、重写隐藏(Name Hiding)示例
隐藏是指派生类中的函数屏蔽了基类中同名函数,无论参数是否相同:
示例1:非虚函数同名导致隐藏
#include <iostream> using namespace std; class Base { public: void show(int x) { // 非虚函数 cout << "Base::show(int): " << x << endl; } void display() { // 非虚函数 cout << "Base::display()" << endl; } }; class Derived : public Base { public: // 与基类show函数参数不同,导致隐藏 void show(double x) { cout << "Derived::show(double): " << x << endl; } // 与基类display函数参数相同,同样导致隐藏 void display() { cout << "Derived::display()" << endl; } }; int main() { Derived d; d.show(3.14); // 调用派生类的show(double) // d.show(10); // 错误!基类的show(int)被隐藏 d.display(); // 调用派生类的display() // 要调用基类被隐藏的函数,必须显式指定 d.Base::show(10); // 显式调用基类的show(int) d.Base::display(); // 显式调用基类的display() return 0; }
输出结果:
Derived::show(double): 3.14 Derived::display() Base::show(int): 10 Base::display()
示例2:虚函数参数不同导致隐藏(而非重写)
#include <iostream> using namespace std; class Base { public: virtual void func(int x) { // 基类虚函数 cout << "Base::func(int): " << x << endl; } }; class Derived : public Base { public: // 函数名相同但参数不同,不构成重写,而是隐藏 void func(double x) { cout << "Derived::func(double): " << x << endl; } }; int main() { Base* basePtr = new Derived(); Derived* derivedPtr = new Derived(); // 调用基类版本,因为派生类没有重写func(int) basePtr->func(10); // 输出"Base::func(int): 10" // 调用派生类版本 derivedPtr->func(3.14); // 输出"Derived::func(double): 3.14" // derivedPtr->func(10); // 错误!基类的func(int)被隐藏 // 显式调用基类函数 derivedPtr->Base::func(10); // 输出"Base::func(int): 10" delete basePtr; delete derivedPtr; return 0; }
输出结果:
Base::func(int): 10 Derived::func(double): 3.14 Base::func(int): 10
这些示例清晰展示了重载、重写覆盖和重写隐藏的区别,重点在于理解它们的作用域、函数签名要求以及多态行为的差异。
- 1