C++的成员函数有重载、覆盖、隐藏三种情况.如不清楚概念,很容易犯错。
首先明确重载、覆盖、隐藏对应的情况:
重载:函数被重载
- 函数名相同
- 参数不同
- virtual关键字可有可无.
以上这种情况我们称之为重载.注意:这种情况并不是只有在类里才会出现.
覆盖:派生类函数覆盖基类函数
- 不同的类(派生类和基类之间)
- 函数名字相同
- 参数相同
- 基类函数有virtual关键字.
以上这种情况称为覆盖.注意:必须有virtual关键字.
隐藏:派生类函数的存在导致基类函数被隐藏.
有两种情况:
- 函数同名,参数不同,无论有无virtual关键字.
- 函数同名,参数相同,基类无virtual关键字.
重载示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <iostream> using namespace std; void output(int x) { cout << "int:" << x << endl; } void output(double x) { cout << "double:" << x << endl; } int main() { int x = 1; double y = 2; output(x); output(y); output(1); output(0.5); } |
这里OutPut函数重载了.不同的参数分别调用了不同的参数的函数.
类成员函数的重载、覆盖、隐藏示例:
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 |
#include <iostream> using namespace std; class Base { public: void f(int x) { cout << "Base::F(int):" << x << endl; } void f(float x) { cout << "Base::F(float):" << x << endl; } void f(double x) { cout << "Base::F(double):" << x << endl; } virtual void g(void) { cout << "Base::g(void)" << endl; } void h(void) { cout << "Base::h(void)" << endl; } }; class Derived : public Base { public: virtual void g(void) { cout << "Derived::g(void)" << endl; } void g(int x) { cout << "Derived::g(int):" << x << endl; } void h(void) { cout << "Derived::h(void)" << endl; } void h(int x) { cout << "Derived::h(int):" << x << endl; } }; int main() { Derived d; Base b; Base * pb = &b; Base * pd = &d; Base & ib = b; Base & id = d; pb->f(42); pb->f(3.14f); pb->f(3.14); cout << endl; pb->g(); pd->g(); ib.g(); id.g(); b.g(); d.g(); cout << endl; pb->h(); pd->h(); ib.h(); id.h(); d.g(1); d.h(); d.h(1); b.h(); } |
Base类中f()是重载。
g()是覆盖
h()是隐藏
我们可以看到:
- 重载的情况下:调用对应参数的函数
- 覆盖的情况下:根据动态联编(动态绑定),实际是基类对象就调用基类函数,实际是子类对象就调用子类函数,与指针或引用形式无关。
- 隐藏的情况下:指针或引用是基类调用对应基类函数,指针或引用是子类调用对应子类的函数。无相应函数时报错.与指向的对象的实际类型无关。
动态绑定:(动态联编)
当我们使用基类的指针或引用调用一个虚函数时,将发生动态绑定。
在C++语言中,基类必须将它的两种成员函数分开,一种是基类希望其派生类进行覆盖的函数,另一种是基类希望派生类直接继承而不覆盖的函数。对于前者,基类通常将其定义为虚函数(virtual)。当我们使用引用或指针调用虚函数时,该调用将被动态绑定,根据引用或指针所绑定的对象类型的不同,该调用可能执行基类的版本,也可能执行某个派生类的版本。
【C++】重载、覆盖与隐藏 & 动态联编(动态绑定)