
文章目录函数的重载、重定义、重写重载overload重定义/隐藏hide重写override重写实现中的最佳实践函数的重载、重定义、重写c中的多态性包含静态多态、动态多态。静态多态在编译阶段进行决议常见的实现方式有重载、模板动态多态在运行阶段进行决议常见的实现方式是重写。重定义是一种用于隐藏基类中函数的手段所以又称为隐藏。覆盖并不是一种统一的翻译有的地方被翻译成重定义的别称有的地方被翻译成重写的别称有歧义。重载overload重载的作用是让函数在使用的时候仅通过传递不同的参数即可调用不同的函数。函数的重载的判定条件在同一个类中进行函数名相同函数参数列表不同class MyClass { public: void func() {} void func(int x) {} void func(double x) {} void func(int x, int y) {} } // 调用 MyClass *my_class new MyClass(); my_class-func(); my_class-func(1); my_class-func(1.0); my_class-func(1, 2);重定义/隐藏hide重定义的作用是隐藏基类中的某些函数。函数重定义的判定条件在派生类与基类中进行派生类对基类中的函数进行重新定义函数名相同// 基类 class Base { public: Base() {} void test() {} }; // 派生类 class Derive : public Base { public: Derive() {} void test() {} }; // 调用 Base* base_class new Base(); // 基类对象 base_class-test(); // 调用 Base::test() Derive* derive_class new Derive(); // 子类对象 derive_class-test(); // 调用 Derive::test()值得注意的是派生类对基类的同名函数进行重定义时基类中所有的该同名函数的重载版本也会被隐藏// 基类 class Base { public: Base() {} void test() {} void test(int x) {} }; // 派生类 class Derive : public Base { public: Derive() {} void test() {} }; // 调用 Base* base_class new Base(); // 基类对象 base_class-test(1); // 调用 Base::test(int) Derive* derive_class new Derive(); // 子类对象 derive_class-test(1); // 编译出错因为基类中名为 test 的重载函数已经被隐藏如果子类对象需要使用基类已经被隐藏的函数可以使用基类名作用域解析运算符函数名的方式来访问derive_class-Base::test(1); // 调用 Base::test(int)或者在子类中使用using关键字来暴露基类接口若此时某个函数在子类和基类中具有相同的函数签名则调用的函数取决于调用者的直接类型即指针对象的调用取决于指针类型而非实际类型// 基类 class Base { public: Base() {} void test() {} void test(int x) {} }; // 派生类 class Derive : public Base { public: Derive() {} void test() {} using Base::test; // 暴露基类所有名为test的接口 }; // 调用 Base* base_class new Base(); // 基类对象 base_class-test(1); // 调用 Base::test(int) Derive* derive_class new Derive(); // 子类对象 derive_class-test(1); // 调用 Derive::test(int) Base* base_class_2 new Derive(); // 基类指针持有子类对象 base_class_2-test(1); // 调用 Base::test(int),因为直接类型为Base重写override重写的作用是在运行时让程序根据对象的实际类型调用对应的函数。依赖继承虚函数机制在运行时通过虚表vtable和虚指针vptr动态绑定。重写的判定条件在派生类与基类中进行派生类对基类中的函数进行重新声明函数名相同函数参数列表相同函数返回值类型相同或类型协变被重写的函数是虚函数virtual关键字// 基类 class Base { public: Base() {} void test() {} virtual void test(int x) {} }; // 派生类 class Derive : public Base { public: Derive() {} void test(int x) {} }; // 调用 Base* base_class new Base(); // 基类对象 base_class-test(1); // 调用 Base::test(int), 根据实际基类类型调用 Base* base_class_2 new Derive(); // 基类指针持有子类对象 base_class_2-test(1); // 调用 Derive::test(int)根据实际子类类型调用子类对基类函数的重写也会导致基类中的同名重载函数被隐藏但此时子类对象依然可以使用基类名域解析运算符的方式来访问基类函数Derive* derive_class new Derive(); // 子类对象 derive_class-test(); // 编译出错因为基类中名为 test 的重载函数已经被隐藏 derive_class-Base::test(); // 调用 Base::test()若此时在子类中使用using关键字来暴露基类接口在实际调用时会对满足重写判定的情况产生二义性导致编译报错// 基类 class Base { public: Base() {} void test() {} virtual void test(int x) {} }; // 派生类 class Derive : public Base { public: Derive() {} void test(int x) {} using Base::test; // 暴露基类所有名为test的接口 }; // 调用 Base* base_class new Base(); // 基类对象 base_class-test(1); // 调用 Base::test(int), 根据实际基类类型调用 Base* base_class_2 new Derive(); // 基类指针持有子类对象 base_class_2-test(1); // 编译出错编译器对调用的函数产生二义性重写实现中的最佳实践在子类中进行重写的地方使用override关键字让编译器进行重写检查不成功时编译器会报错防止重写失误。class Derive : public Base { public: Derive() {} void test(int x) override {} // 让编译器进行重写检查 };