C++深度解析 C++对象模型分析(下) --- 继承对象模型,多态对象模型,虚函数表,用C语言实现多态(50)

C++深度解析 C++对象模型分析(下) --- 继承对象模型,多态对象模型,虚函数表,用C语言实现多态(50)

继承对象模型

在C++编译器的内部类可以理解为结构体

子类是由 父类成员 叠加 子类新成员 得到的。

代码如下:继承对象模型初探

#include <iostream>
#include <string>

using namespace std;

class Demo
{
protected:
    int mi;
    int mj;
};

class Derived : public Demo
{
    int mk;
public:
    Derived(int i, int j, int k)
    {
        mi = i;
        mj = j;
        mk = k;
    }
    
    void print()
    {
        cout << "mi = " << mi << ", "
             << "mj = " << mj << ", "
             << "mk = " << mk << endl;
    }
};

struct Test
{
    int mi;
    int mj;
    int mk;
};

int main()
{
    cout << "sizeof(Demo) = " << sizeof(Demo) << endl;  // 8
    cout << "sizeof(Derived) = " << sizeof(Derived) << endl;  // 12
    
    Derived d(1, 2, 3);
    //把一个指针类型重新解释为另一个指针类型
    Test* p = reinterpret_cast<Test*>(&d);
    
    cout << "Before changing ..." << endl;
    d.print();
    
    //通过指针p改变d对象成员变量的值
    p->mi = 10;
    p->mj = 20;
    p->mk = 30;
    
    cout << "After changing ..." << endl;
    
    d.print();
    
    return 0;
}

结果如下:

分析:

成员函数存放在代码段,实际对象只包含成员变量。

继承对象模型,父类成员变量叠加子类新定义成员变量,父类成员变量排在前面,子类新定义成员变量排在后面。

多态对象模型

多态与虚函数的区别:

多态:面向对象理论中的一个概念,相同的行为方式,不同的行为结果,表现多种形态。

虚函数:多态的表现形式由虚函数实现。

C++多态的实现原理

  • 当类中声明虚函数时,编译器会在类中生成一个虚函数表
  • 虚函数表是一个存储成员函数地址的数据结构
  • 虚函数是由编译器自动生成与维护的
  • virtual成员函数会被编译器放入虚函数表
  • 存在虚函数时,每个对象中都有一个指向虚函数表的指针
void run(Demo* p, int v)
{
    p->add(v);
}

编译器确认run()是否为虚函数:

如果run是虚函数,编译器在对象VPTR所指向的虚函数表中查找add()的地址

如果run不是虚函数,编译器直接可以确定被调用成员函数的地址

代表如下:

#include <iostream>
#include <string>

using namespace std;

class Demo
{
protected:
    int mi;
    int mj;
public:
    //里面存在一个虚函数表指针
    virtual void print()
    {
        cout << "mi = " << mi << ", "
             << "mj = " << mj << endl;
    }
};

class Derived : public Demo
{
    int mk;
public:
    Derived(int i, int j, int k)
    {
        mi = i;
        mj = j;
        mk = k;
    }
    
    void print()
    {
        cout << "mi = " << mi << ", "
             << "mj = " << mj << ", "
             << "mk = " << mk << endl;
    }
};

struct Test
{
    void *p; //指向虚函数表的指针
    int mi;
    int mj;
    int mk;
};

int main()
{
    cout << "sizeof(Demo) = " << sizeof(Demo) << endl;
    cout << "sizeof(Derived) = " << sizeof(Derived) << endl;
    
    Derived d(1, 2, 3);
    //把一个指针类型重新解释为另一个指针类型
    Test* p = reinterpret_cast<Test*>(&d);
    
    cout << "Before changing ..." << endl;
    d.print();
    
    //通过指针p改变d对象成员变量的值
    p->mi = 10;
    p->mj = 20;
    p->mk = 30;
    
    cout << "After changing ..." << endl;
    
    d.print();
    
    return 0;
}

结果如下:

分析:

当创建对象时,如果类里面有虚函数,最终生成对象时,会被编译器强行塞入一个指针成员变量,这个指针成员变量是不可见的,但是它确实存在,这个指针成员变量指向虚函数表。

 

用C语言实现面向对象,用C语言实现多态

代码如下:

50-2.h

#ifndef _50_2_H_

#define _50_2_H_



typedef void Demo;

typedef void Derived;//子类



Demo* Demo_Create(int i, int j);

int Demo_GetI(Demo* pThis);

int Demo_GetJ(Demo* pThis);

int Demo_Add(Demo* pThis, int value);

void Demo_Free(Demo* pThis);


//子类成员函数

Derived* Derived_Create(int i, int j, int k);

int Derived_GetK(Derived* pThis);

int Derived_Add(Derived* pThis, int value);//虚函数



#endif

50-2.c

#include "50-2.h"

#include "malloc.h"


//定义一个全局的虚函数,这个函数在当前文件能访问
static int Demo_Virtual_Add(Demo* pThis, int value);
static int Derived_Virtual_Add(Demo* pThis, int value);

//用结构体来表示虚函数表
struct VTable      //2. 定义虚函数表数据结构
{
    //函数指针
    int (*pAdd)(Derived*, int);   //3. 虚函数表里面存储什么???
};


struct ClassDemo

{
    struct VTable* vptr;//1. 定义虚函数表指针 ==》 虚函数表指针类型???

    int mi;

    int mj;

};



//父类的成员变量叠加子类的成员变量

struct ClassDerived

{

    //最开始的部分为父类

    struct ClassDemo d;

    int mk;

};


//虚函数表变量,用送她题材
static struct VTable g_Demo_vtbl = 
{
    Demo_Virtual_Add
};

static struct VTable g_Derived_vtbl = 
{
    Derived_Virtual_Add
};


Demo* Demo_Create(int i, int j)

{

    struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo));

    

    if( ret != NULL )

    {
        //指向虚函数表
        ret->vptr = &g_Demo_vtbl;   //4. 关联对象和虚函数表

        ret->mi = i;

        ret->mj = j;

    }

    

    return ret;

}



int Demo_GetI(Demo* pThis)

{

     struct ClassDemo* obj = (struct ClassDemo*)pThis;

     

     return obj->mi;

}



int Demo_GetJ(Demo* pThis)

{

    struct ClassDemo* obj = (struct ClassDemo*)pThis;

     

    return obj->mj;

}


//6. 定义虚函数表中指针所指向的具体函数
static int Demo_Virtual_Add(Demo* pThis, int value)
{
    struct ClassDemo* obj = (struct ClassDemo*)pThis;

     

    return obj->mi + obj->mj + value;
}

//5. 分析具体的虚函数!!!!

int Demo_Add(Demo* pThis, int value)

{

    struct ClassDemo* obj = (struct ClassDemo*)pThis;

     
    //通过对象,找到虚函数表的指针,然后在虚函数表中找到具体调用函数的地址

    return obj->vptr->pAdd(pThis, value);

}



void Demo_Free(Demo* pThis)

{

    free(pThis);

}



//子类构造函数

Derived* Derived_Create(int i, int j, int k)

{

    struct ClassDerived* ret = (struct ClassDerived*)malloc(sizeof(struct ClassDerived));

    

    if( ret != NULL )

    {
        ret->d.vptr = &g_Derived_vtbl;
        //初始化父类

        ret->d.mi = i;

        ret->d.mj = j;
        //初始化子类
        ret->mk = k;

    }

    

    return ret;

}



int Derived_GetK(Derived* pThis)
{
    struct ClassDerived* obj = (struct ClassDerived*)pThis;

     

    return obj->mk;
}

static int Derived_Virtual_Add(Demo* pThis, int value)
{
    struct ClassDerived* obj = (struct ClassDerived*)pThis;

     

    return obj->mk + value;
}


int Derived_Add(Derived* pThis, int value)
{
    struct ClassDerived* obj = (struct ClassDerived*)pThis;

     

    return obj->d.vptr->pAdd(pThis, value);
}

main.c

#include "stdio.h"

#include "50-2.h"


void run(Demo* p, int v)
{
    int r = Demo_Add(p, 3);
    
    printf("r = %d\n", r);
}


int main()

{
    //创建父类对象
    Demo* pb = Demo_Create(1, 2);
    //创建子类对象
    Derived* pd = Derived_Create(1, 22, 333);
    
    printf("pb->add(3) = %d\n", Demo_Add(pb, 3));
    printf("pd->add(3) = %d\n", Derived_Add(pd, 3));
    
    run(pb, 3);
    run(pd, 3);
    
    Demo_Free(pb);
    Demo_Free(pd);
    

    return 0;

}

结果如下:

小结:

继承的本质就是父子间成员变量的叠加

C++中的多态是通过虚函数表实现的

虚函数表是由编译器自动生成与维护的

虚函数的调用效率低于普通成员函数

猜你喜欢

转载自blog.csdn.net/xiaodingqq/article/details/86255828