技术交流QQ群:1027579432,欢迎你的加入!

1.C++中的多态

  • 多态: 同一个事物在不同场景下的多种形态


    多态分类.png

2.静态多态

  • 函数重载就是一个简单的静态多态,如下面的例子:
        // 静态多态
        int Add(int a, int b){
            return a+b;
        }
        double Add(double a, int b){
            return a+b;
        }
    
        int main(){
            Add(10, 20);
            Add(10.0, 20);
            return 0;
        }
    
  • 总结:静态多态是编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函数,如果有合适的函数可以调用就调,没有的话就会发出警告或者报错。

3.动态多态

  • 动态多态: 它是在程序运行时根据基类的引用(指针)指向的对象来确定自己具体该调用哪一个类的虚函数,见下面的例子:
        // 动态多态
        class TakeBus{
            public:
                void TakeBusToSubway(){
                    cout << "go to subway\n";
                }
                void TakeBusToStation(){
                    cout << "go to station\n";
                }
        };
    
        class Bus{
            public:
                virtual void TakeBusToSomewhere(TakeBus& tb) = 0;   // 纯虚函数,Bus是个抽象类,提供一个接口
        };
    
        class Subway: public Bus{
            public: 
                virtual void TakeBusToSomewhere(TakeBus& tb){  // 虚函数
                    tb.TakeBusToSubway();
                }
        };
    
        class Station: public Bus{
            public:
                virtual void TakeBusToSomewhere(TakeBus& tb){   // 虚函数
                    tb.TakeBusToStation();
                }
        };
    
    
    
        int main(){
            TakeBus tb;
            Bus *b = NULL;
            for(int i = 1; i <= 10; ++i){
                if((rand() % i) & 1)
                    b = new Subway();
                else    
                    b = new Station();
            }
            b->TakeBusToSomewhere(tb);
            delete b;
            return 0;
        }
    
  • 从上面的例子还发现在每一个函数前都加了virtual这个虚拟关键字,它是在程序运行时根据条件去选择调用哪一个函数,参加下面的例子:
        // 动态多态2
    
        // 基类
        class Base{
            public:
                virtual void fun(int i){  // fun在基类中被声明是虚函数,可以动态绑定,根据传入的派生类对象进行调用对应的成员函数
                    cout << "Base::fun()\n";
                }
                void fun1(int i){  // fun1在基类中没有被声明是虚函数,不能动态绑定
                    cout << "Base::fun1()\n";
                }
        };
    
        class Derived: public Base{
            public:
                virtual void fun(int i){
                    cout << "Derived::fun()\n";
                }
                virtual void fun1(int i){
                    cout << "Derived::fun1()\n";
                }
                void fun2(int i){
                    cout << "Derived::fun2()\n";
                }
        };
        // 全局函数
        void TestVirtual(Base& b){
            b.fun(0);
            b.fun1(1);
        }
    
    
        int main(){
            Base b1;
            Derived d1;
            TestVirtual(b1);
            TestVirtual(d1);
    
            return 0;
        }
    
  • 动态多态的条件:
    • 基类中必须包含虚函数,并且派生类中一定要对基类中的虚函数进行重写
    • 通过基类对象的指针或者引用调用虚函数
  • 函数重写:
    • 基类中将被重写的函数必须为虚函数
    • 基类和派生类中虚函数的原型必须保持一致(返回值类型,函数名称以及参数列表),协变[基类(或者派生类)的虚函数返回基类(派生类)的指针(引用)]和析构函数(基类和派生类的析构函数是不一样的)除外
    • 访问限定符可以不同
  • 哪些函数不能定义为虚函数?
    • 友元函数,它不是类的成员函数
    • 全局函数
    • 静态成员函数,它没有this指针
    • 构造函数,拷贝构造函数,以及赋值运算符重载(可以但是一般不建议作为虚函数)

4.抽象类

  • 在成员函数(必须为虚函数)的形参列表后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。纯虚函数是一定要被继承的,否则它存在没有任何意义。

5.参考博客