重载重写与覆盖

覆盖与重写、重载区别是什么?effective cpp 条款33

重载

重载从overload翻译过来,是指同一可访问区内被声明的 几个具有不同参数列表(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型。

  1. 相同的范围(在同一个作用域中)
  2. 函数名字相同
  3. 参数不同列表
  4. virtual 关键字可有可无
  5. 返回类型可以不同
1
2
3
4
5
6
int test();
int test(int a);
int test(int a,double b);
int test(double a,int a);
int test(string s);
...

重写

重写翻译自override,是指派生类中存在重新定义的函数。其 函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。

  1. 不在同一个作用域(分别位于派生类与基类)
  2. 函数名字相同
  3. 参数相同列表(参数个数,两个参数列表对应的类型)
  4. 基类函数必须有 virtual 关键字,不能有 static,大概是多态的原因吧…
  5. 返回值类型相同(或者协变),否则报错
  6. 重写函数的访问修饰符可以不同。尽管 virtualprivate 的,派生类中重写改写为 public,protected 也是可以的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Base{
public:
virtual void test(int a)
{
cout<<"this is base"<<endl;
}
};

class Ship:public Base
{
public:
void test(int a)
{
cout<<"this is Base overwrite function"<<endl;
}
};

协变 covariant

在C++中,协变(covariant)或者 返回类型协变(return type covariance,体现在:派生类中的返回类型可以是基类(父类)中返回类型的子类型。

换句话说,如果一个虚函数在基类中返回的是基类类型的指针或引用,那么派生类可以重写该虚函数并返回基类类型的子类类型的指针或引用。

派生类中重写的虚函数可以具有比基类更具体的返回类型。

这种协变的能力使得在使用多态时更加灵活,可以根据具体的派生类返回不同的子类型,而不需要进行显式的类型转换。

覆盖(隐藏)

隐藏是指 派生类的函数屏蔽了与其同名的基类函数。注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。

  1. 不在同一个作用域(分别位于派生类与基类)
  2. 函数名字相同
  3. 返回类型可以不同
  4. 参数不同,此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)而不是被重写
  5. 参数相同,但是基类函数有无virtual关键字都会被隐藏。此时,基类的函数被隐藏(注意别与覆盖混淆)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
using namespace std;

class Base
{
public:
virtual void test()//有virtual关键字,参数列表不同
{
cout<<"this is base there are different parameters with virtual"<<endl;
}

void test1()
{
cout<<"this is base with the same parameters with not virtual"<<endl;
}

virtual void test2()
{
cout<<"this is base with the same parameters with virtual"<<endl;
}
};

class Ship:public Base
{
public:
void test()
{
cout<<"this is Ship there are different parameters with virtual cover"<<endl;
}

void test1()
{
cout<<"this is Ship with the same parameters with not virtual cover"<<endl;
}

void test2()
{
cout<<"this is Ship with the same parameters with virtual cover"<<endl;
}
};

int main()
{
Ship s;
s.test();
s.test1();
s.test2();
cout<<endl;

Base* pb = new Ship();
pb->test();
pb->test1();
pb->test2();

cout<<endl;
pb = new Base();
pb->test();
pb->test1();
pb->test2();
return 0;
}

总结

重载代表了静态多态,在同一作用域下,同名函数可以表现出不同的行为;

重写则是动态多态,不同作用域(基类和派生类)下,通过对象指针或引用,使得同名同参函数展现出不同行为;

覆盖则是不同作用域下的名称掩盖(隐藏),要求使用派生对象调用函数。

作者

Desirer

发布于

2025-05-25

更新于

2025-07-20

许可协议