重载
- 相同的范围(在同一个类中)
- 函数名相同
- 参数不同
- virtual关键字可有可无
重载与继承、隐藏很好区分,因为重载函数在同一个类中
举例说明
#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;} }; int main() { Base b; b.f(42); b.f(3.14f); }
结果
继承
- 不同的范围(分别位于基类和派生类)
- 函数名相同
- 参数相同
- 基类必须有virtual关键字
隐藏
- 如果派生类的函数与基类的函数同名、同参数,基类函数不带有virtual关键字
- 如果派生类函数与基类的函数同名、不同惨,不管基类函数带不带virtual关键字
归纳起来
同名前提(不同名免谈)
- 同参+virtual——继承
- 同参+无virtual / 不同参 —— 隐藏
强调:只要不是继承(virtural+同参)就是隐藏,隐藏后,如果基类、派生类有相同函数名,派生类对象只能调用派生类的函数。
#include <iostream> #include <string> using namespace std; class base { public: virtual void test(int a, int b) { cout << a << " " << b << endl; } }; class derived : public base { public: void test(int a) { cout << a << endl; } //隐藏 }; int main() { derived m; m.test(45); m.test(4, 5); //error:派生类中没有俩参数的 }
#include <iostream> #include <string> using namespace std; class base { public: void test(int a, int b) { cout << a << " " << b << endl; } }; class derived : public base { public: void test(int a) { cout << a << endl; } //隐藏 }; int main() { derived m; m.test(45); m.test(4, 5); //error:派生类中没有俩参数的 }
举例说明
#include <iostream> using namespace std; class Base { public: virtual void f(float x) {cout << "Base f" << x << endl;} void g(float x) {cout << "Base g" << x << endl;} void h(float x) {cout << "Base h" << x << endl;} }; class Derived : public Base { public: void f(float x) {cout << "Derived f" << x << endl;} //同参 + virtual —— 继承 void g(int x) {cout << "Derived g" << x << endl;} //不同惨 ——隐藏 void h(float x) {cout << "Derived h" << x << endl;} //同参 + 无virtual ——隐藏 }; int main() { Derived d; Base *pb = &d; Derived *pd = &d; pb->f(3.14f); pd->f(3.14f); pb->g(3.14f); pd->g(3.14f); pb->h(3.14f); pd->h(3.14f); }
结果
举例说明虚函数、隐藏的区别
#include <iostream> #include <string> using namespace std; class base { public: virtual void test() { cout << "test base" << endl; } void test_1() { cout << "test_1 base" << endl; } }; class derived : public base { public: void test() { cout << "test derived" << endl; } //虚函数 void test_1() { cout << "test_1 derived" << endl; } //隐藏 }; int main() { derived d1, d2; base *p1 = &d1; base *p2 = &d2; p1->test(); p2->test_1(); }
结果
分析
动态绑定必须通过基类的引用或指针调用虚函数(virtual)。当这样做时,编译器将在基类中查找virtual函数。
假如找到了(同名、同参):就在其派生类中找对应的函数(这就是为什么必须在基类和派生类中特点是:同名、同参)。
- 如果找到了就调用派生类的函数
- 否则乖乖的用基类的虚函数
假如没找到对应的virtual,就找对应的函数(同名同参),这回只能在父类中倒腾了,因为根本没法通过virtual穿越到子类。
隐藏就不同了,如果基类中连函数原型都没有,就直接报错了。如果有:直接调用就得啦(没有virtural没法对应派生类的重定义的函数)。