0%

C++ 重载、覆盖(重写)、隐藏(重定义)

参考文章:c++三大概念要分清–重载,隐藏(重定义),覆盖(重写)


重载

在同一个作用域内
1. 函数名相同
2. 参数列表不同(参数个数不同,或者参数类型不同,或者参数个数和参数类型都不同)
3. 返回值类型可相同也可不同

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
test_ooh.cpp

namespace {

int Add(int a, int b)
{
PRINT_INFO("int " << __func__ << "(int, int)");
return a + b;
}

double Add(double a, double b)
{
PRINT_INFO("double " << __func__ << "(double, double)");
return a + b;
}

}

class test_ooh
{
public:
test_ooh(){}
~test_ooh(){}

int Add(int a, int b)
{
PRINT_INFO("int " << "test_ooh::" << __func__ << "(int, int)");
return a + b;
}

double Add(double a, double b)
{
PRINT_INFO("double " << "test_ooh::" << __func__ << "(double, double)");
return a + b;
}
};

/* code */
Add(1, 2);
Add(1.2, 3.2);

test_ooh to;
to.Add(1, 2);
to.Add(1.3, 2.2);

输出结果:

[INFO]: int Add(int, int)
[INFO]: double Add(double, double)
[INFO]: int test_ooh::Add(int, int)
[INFO]: double test_ooh::Add(double, double)
  • 匿名 namespace 下的两个函数 Add() ,在同一作用域,函数名相同,参数类型不同,就构成了 C++ 中的函数重载;
  • 调用函数名相同的函数,会根据 实参的类型和实参顺序以及实参个数选择相应的函数
  • C++ 函数重载是一种 静态多态(又叫做静态联编,静态绑定,静态决议)

重写(覆盖)

不在同一个作用域内(分别在父类和子类):
1. 函数名相同
2. 参数列表相同
3. 返回值类型相同(协变除外)
4. 基类函数必须有 virtual 修饰(即虚函数)
5. 父子类中的函数的访问修饰符可以不同

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
62
63
64
65
66
67
test_ooh.cpp

class Base
{
public:
Base(){}
~Base(){}

//普通重写
virtual void show()
{
PRINT_INFO("Base::show()");
}

//协变重写,返回指针也可
virtual Base& getThis()
{
PRINT_INFO("Base::getThis()");
return *this;
}

};

class Derived : public Base
{
public:
Derived(){}
~Derived(){}

//普通重写
virtual void show()
{
PRINT_INFO("Derived::show()");
}

//(virtual可省略)协变重写,返回指针也可
Derived& getThis()
{
PRINT_INFO("Derived::getThis()");
return *this;
}

};

//重载
namespace {
void callFunc(Base& b)
{
b.show();
b.getThis();
}

void callFunc(Base* b)
{
b->show();
b->getThis();
}
}

Base b;
Derived d;

callFunc(b);
callFunc(d);
callFunc(&b);
callFunc(&d);

输出结果:

[INFO]: Base::show()
[INFO]: Base::getThis()
[INFO]: Derived::show()
[INFO]: Derived::getThis()
[INFO]: Base::show()
[INFO]: Base::getThis()
[INFO]: Derived::show()
[INFO]: Derived::getThis()
  • 父类函数为虚函数;
  • 当在子类中定义了一个与父类完全相同的虚函数时,则称子类的这个函数重写(也称覆盖)了父类的这个虚函数;(子类中的虚函数和父类中的虚函数,函数名,参数个数,参数类型,返回值类型都相同;这种情况下子类的这个虚函数重写的父类中的虚函数,构成了重写)
  • 协变 ——— 是说子类中的虚函数和父类中的虚函数,函数名,参数个数,参数类型都相同,只是返回值类型不同;父类的虚函数返回父类的指针或者引用,子类虚函数返回子类的指针或者引用;这种情况下子类的这个虚函数也重写了父类中的虚函数,也构成了重写;———— 我们把这种特殊的情况叫做协变

重定义(隐藏)

不在同一个作用域内(分别在父类和子类):
1. 函数名相同
2. 在父类和子类中只要不构成重写的都是重定义
3. 重定义的不光是类的成员函数,还可以是类的成员变量

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
test_ooh.cpp

class Base
{
public:
Base():i_(0){}
Base(int i):i_(i){}
~Base(){}

//普通重写
virtual void show()
{
PRINT_INFO("Base::show()");
}

//协变重写,返回指针也可
virtual Base& getThis()
{
PRINT_INFO("Base::getThis()");
return *this;
}

//重定义
virtual void test_hiding()
{
PRINT_INFO("Base::test_hiding()");
}

//重定义
void test_show(int a)
{
PRINT_INFO("Base::test_show(int) , a = " << a);
}

//重定义
int test_hiding2()
{
PRINT_INFO("Base::test_hiding2()");

return 0;
}

public:
int i_;

};

class Derived : public Base
{
public:
Derived(){}
Derived(int i):Base(i),i_(0){}
~Derived(){}

//普通重写
virtual void show()
{
PRINT_INFO("Derived::show()");
}

//(virtual可省略)协变重写,返回指针也可
Derived& getThis()
{
PRINT_INFO("Derived::getThis()");
return *this;
}

//重定义
void test_hiding(int a)
{
PRINT_INFO("Derived::test_hiding(int) , a = " << a);
}

//重定义
void test_show(int a, int b)
{
PRINT_INFO("Derived::test_show(int) , a = " << a << ",b = " << b);
}

//重定义
void test_hiding2()
{
PRINT_INFO("Derived::test_hiding2()");
}

public:
int i_;

};

Base b1;
Derived d1(1);
b1.test_hiding();
d1.Base::test_hiding();
d1.test_hiding(1);

PRINT_INFO("Derived::i_ = " << d1.i_);
PRINT_INFO("Base::i_ = " << d1.Base::i_);

b1.test_show(1);
d1.Base::test_show(1);
d1.test_show(1, 2);

b1.test_hiding2();
d1.Base::test_hiding2();
d1.test_hiding2();

输出结果:

[INFO]: Base::test_hiding()
[INFO]: Base::test_hiding()
[INFO]: Derived::test_hiding(int) , a = 1
[INFO]: Derived::i_ = 0
[INFO]: Base::i_ = 1
[INFO]: Base::test_show(int) , a = 1
[INFO]: Base::test_show(int) , a = 1
[INFO]: Derived::test_show(int) , a = 1,b = 2
[INFO]: Base::test_hiding2()
[INFO]: Base::test_hiding2()
[INFO]: Derived::test_hiding2()