C++重载、重写、重定义
- 重载、重写、重定义对比
- 一、重载(overload)
- 二、重写 / 覆盖(override)
- 三、重定义 / 隐藏(redefining)
- * 为什么在虚函数中不能使用 static 关键字?
- 动态绑定(Dynamic Binding)
- 静态成员函数
- conclusion
- * 重写函数的访问修饰符可以不同吗?
- 缩小访问权限
- 放宽访问权限
重载、重写、重定义对比
一、重载(overload)
指函数名相同,但是它的参数表列个数或顺序,类型不同。但是不能靠返回类型来判断。
(1)在同一个作用域中
(2)函数名字相同
(3)参数列表不同(参数个数,参数类型,类型顺序…)
(4)virtual 关键字可有可无
(5)返回值可以相同也可以不同
二、重写 / 覆盖(override)
指派生类中有一个跟基类(返回值类型(除了协变),函数名,参数列表)相同的虚函数,特征是:
(1)两个虚函数分别位于派生类与基类
(2)函数名字相同
(3)参数列表相同
(4)基类函数必须在函数前面加 virtual
关键字,不能有 static
(5)返回值相同(除了协变)
(6)重写函数的访问修饰符可以不同
(派生类中重写的函数可以放宽其在基类中的访问修饰符,尽管基类虚函数是 private 的,派生类中重写改写为 public,protected 也是可以的)
三、重定义 / 隐藏(redefining)
(1)两函数分别位于派生类与基类
(2)函数名字相同
(3)返回值可以不同
(4)参数列表不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别跟重载混淆,首先作用域就不同,重载要求在同一作用域) 。
(5)参数相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏。
(6)隐藏的函数不具备多态性。
两个同名函数分别位于派生类与基类,不是构成重写就是构成重定义。
* 为什么在虚函数中不能使用 static 关键字?
为什么在虚函数中不能使用 static 关键字呢?
这需要考虑两者的特性——
在C++中,虚函数和静态成员函数有不同的语义和用途,因此它们在语法上是互斥的。
动态绑定(Dynamic Binding)
虚函数的一个关键特性是动态绑定(也称为运行时多态性)。当通过基类的指针或引用调用虚函数时,实际调用的是派生类的版本,这个决定是在运行时根据对象的实际类型进行的——这种机制使得程序能够根据对象的实际类型执行我们希望的操作。
静态成员函数
静态成员函数属于类而不是类的实例。
静态成员函数在整个类中是共享的。
静态成员函数在编译时就被解析,因为它们不依赖于对象的实际类型。
conclusion
由于虚函数和静态成员函数具有不同的调用和解析机制,将它们结合在一起可能导致混淆。
在C++中,虚函数是通过虚函数表和虚指针来实现的,而静态成员函数不涉及这些机制~
因此,为了保持语言的一致性和清晰性,C++规定在虚函数声明中不能使用 static 关键字。在使用虚函数时,编译器会使用动态绑定机制,而静态成员函数不参与这种机制,因此在虚函数中使用 static 不合适
* 重写函数的访问修饰符可以不同吗?
派生类中重写基类中的虚函数时,派生类中的函数的访问修饰符可以有一些变化,但有一些限制:
缩小访问权限
派生类中重写的函数可以缩小其在基类中的访问修饰符。
- 如果基类中的虚函数是 public,那么在派生类中可以选择将其重写为 public、protected 或 private。
- 如果基类中的虚函数是 protected,那么在派生类中可以选择将其重写为 protected 或 private。
- 如果基类中的虚函数是 private,则不能在派生类中直接重写。
放宽访问权限
派生类中重写的函数不可以放宽其在基类中的访问修饰符。
例如,如果基类中的虚函数是private,则派生类中重写时不能将其放宽为public。