重载
:::info 是指同⼀可访问区内被声明的几个具有不同参数列表的同名函数,可以是参数类型,个数,顺序的不同. 根据参数列表决定调用哪个函数,重载不关心函数的返回类型 :::
重写 (override)
:::info 派生类中重新定义父类中除了函数体(花括号内的函数定义部分)外完全相同的虚函数 ::: 举例:
class A {public:virtual void fun() { cout << "A"; }};class B :public A {public:virtual void fun() { cout << "B"; }};int main(void) {A* a = new B();a->fun(); //输出B,A类中的fun在B类中重写}
注意:
- 被重写与重写的方法必须方法名相同、参数列表相同、返回值相同;
- 派生类中重写的方法所抛出的异常必须与基类中的重写的方法的异常一致,或者不能比父类的异常范围更大;
- 基类的私有方法不能被重写,若派生类非要重写该同名方法,至少定义了一个与父类方法相同的新方法,而并不是重写父类的方法;
- 被重写的函数不能是 static 的
- 重写和被重写的函数是在不同的类中的,重写函数的访问修饰符是可以不同的,尽管 virtual 中是 private 的,派生类中重写可以改为 public;即派生类中重写方法的访问权限可以 >= 基类;
重定义 (隐藏)
:::info 派⽣类中重新定义父类中同名的的非 virtual 函数,参数列表和返回类型都可以不同 :::
2.0 声明两个仅返回值不同的同名函数,会有什么问题吗?
举例:
class OverloadClass
{
void overload_func(int arg1, double arg2);
int overload_func(int arg1, double arg2);
};
上面代码会报错:
error: ‘int OverloadClass::overload_func(int, double)’ cannot be overloaded with ‘void OverloadClass::overload_func(int, double)’
结论: 会编译报错,因为调用函数时,编译器无法通过返回值类型区分调用的是哪个函数;
2.1 追问: 重载为什么改变参数就可以实现调用不同的函数?(c++是如何支持重载的)
因为C++在编译的时候会对函数进行重命名,保证函数名的唯一性,而重载函数的参数不同,就会被命名为不同的函数名.
例如 int func(int, double)经过重命名后会变成 _func_int_double
具体的是:C++利用命名倾轧(name mangling)技术,来改名函数名,区分参数不同的同名函数。命名倾轧是在编译阶段完成的。
参考:
c++的重载和重写是如何实现的
2.1.1 追问:重载为什么可以忽略函数返回值类型?
简单来说, 因为调用时不能指定返回值类型, 编译器无法知晓你要调用哪个函数.
举例:
:::info
float max(int a, int b);
int max(int a, int b);
:::
当调用max(1, 2);时无法确定调用的是哪一个,单从这一点上来说,仅返回值类型不同的重载是不应该允许的。
总结: 在调用同名函数时, 返回值类型不能作为区分函数唯一性的条件
2.2 追问:构造函数可以被重载吗?
构造函数可以被重载,因为构造函数可以有多个且可以带参数。
构造函数为什么可以有多个?
构造函数主要用来在创建对象时完成对对象属性的一些初始化等操作, 当创建对象时, 对象会自动调用它的构造函数。一般来说, 构造函数有以下三个方面的作用:
1、给创建的对象建立一个标识符;
2、为对象数据成员开辟内存空间;
3、完成对象数据成员的初始化
2.3 追问:析构函数可以被重载吗?
析构函数不可以被重载,因为析构函数只能有一个,且不能带参数。
2.4 追问:假设对基类的函数进行重载,然后派生类中对基类的该重载函数进行隐藏, 派生类中隐藏的函数声明是无参数的,那么我能够通过派生类对象调用到基类的带函数参数列表这个重载的函数吗?
举例:
class Parent {public:/* 基类进行函数重载 */void reloadFunc(int x) { printf("call reloadFunc with int x: %d\n", x); }void reloadFunc(int x, double y) { printf("call reloadFunc with int x double y\n"); }};class Child : public Parent {public:/* 对基类的函数进行隐藏 */void reloadFunc(){}void callParentReloadFunc() { Parent::reloadFunc(4); }};void TestOverLoad(){// 需要调用基类的 reloadFuncChild c;c.callParentReloadFunc();}
结论:可以在派生类中通过类作用域运算符:: 访问基类的重载函数。
