关于虚函数实现多态的原理及分析

2023-08-04,,

这篇文章主要介绍了C++中如何实现多态问题,具有很好的参考价值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

目录
  • 1、C++中如何实现多态
  • 2、虚函数实现多态的原理
    • 2.1 单类继承
    • 2.2 多类继承
    • 示例
  • 总结

    1、C++中如何实现多态

    • 基类中先声明一个虚函数
    • 至少有一个继承该基类的子类

    2、虚函数实现多态的原理

    • 当一个类中出现虚函数或着子类继承了虚函数时,就会在该类中产生一个虚函数表(virtual table),虚函数表实际上是一个函数指针数组(在有的编译器作用下是链表),里面的每一个元素对应指向该类中的某一个虚函数的指针。
    • 被该类声明的对象会包含一个虚函数表指针(virtual table pointer),指向该类的虚函数表的地址。
    • 虚函数的调用过程: 当一个对象要调用到虚函数时,先将对象内存中的vptr指针(虚函数表指针)指向定义该类的vtbl(虚函数表),vtbl再寻找里面的指针指向想要调用的虚函数,从而完成虚函数的调用。

    2.1 单类继承

    定义一个父类

    class Person{
    public:
    	virtual void f(){cout << "use f()" << endl;}
    	virtual void g(){cout << "use g()" << endl;}
    	virtual void h(){cout << "use h()" << endl;}
    };
    

    父类对象其在内存中布局如下:

    • 再定义一个子类,此时并不覆盖父类的虚函数:
    class Bag:public Person{
    public:
    	virtual void i(){cout << "use i()" << endl;}
    	virtual void j(){cout << "use j()" << endl;}
    };
    

    可以看出虚函数表内的虚函数是按声明顺序进行排序的

    父类虚函数排在子类虚函数之前

    • 当我们把子类中的虚函数覆盖掉:(修改Bag类)
    class Bag:public Person{
    public:
    	void f(){cout << "class Bag use fun" << endl;}
    	virtual void i(){cout << "use i()" << endl;}
    	virtual void j(){cout << "use j()" << endl;}
    }; 
    

    子类覆盖的虚函数,放在父类原先放该虚函数的位置上。

    所以当父类指针指向该子类对象时,会调用该子类的重载函数

    2.2 多类继承

    • 子类没有覆盖父类的虚函数

    子类的虚函数放在第一张虚函数表中,紧跟着第一个父类的虚函数

    如果每个父类都有虚函数,则有几个父类就有几张虚函数表

    • 子类覆盖父类的虚函数

    父类的虚函数被子类覆盖后,则该子类对应的重载函数的位置在被覆盖的父类函数的位置上。(如果父类没有该虚函数,则不用被覆盖)

    父类的虚函数被子类覆盖后,则父类指针指向该子类对象时,调用的f()便是子类中重载的f()

    示例

    #include <iostream>
    using namespace std;
    
    class Person1{
    public:
        virtual void f(){}
        virtual void g(){}
        virtual void h(){}
        virtual ~Person1(){}
    };
    
    class Person2{
    public:
        virtual void f(){}
        virtual void g(){}
        virtual void h(){}
        void a(){           // 成员函数,不需要重载
            cout << "class Person2" << endl;
        }
        virtual ~Person2(){}
    };
    
    class Person3{
    public:
        virtual void g(){}
        virtual void h(){}
        virtual ~Person3(){}
    };
    
    class Bag:public Person1, public Person2, public Person3{
    public:
        void f(){
            cout << "Bag f()" << endl;
        }
        void g(){
            cout << "Bag g()" << endl;
        }
        void a(){
            cout << "Class Bag" << endl;
        }
    };
    
    int main(int argc, char const *argv[])
    {
        Person3* p3 = new Bag;
        //p3->f();    // P3 没有成员函数f()
                      // 多态首先得是 父类有虚函数,其次是子类要定义该函数的重载
                      // 如果父类的虚函数改为成员函数,则子类无法进行重载,即无法实现多态
        delete p3;
        p3 = NULL;
    
        Person1* p1 = new Bag;
        p1->f();
        delete p1;
        p1 = NULL;
    
        Person2* p2 = new Bag;
        p2->a();
        delete p2;
        p2 = NULL;
        
        return 0;
    }
    
    

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持北冥有鱼。

    《关于虚函数实现多态的原理及分析.doc》

    下载本文的Word格式文档,以方便收藏与打印。