C语言实现C++的多态

编译时的多态性:编译时的多态性是通过重载函数来实现的。

运行时的多态性:运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C++中,运行时的多态性通过虚成员实现。

参考:https://blog.csdn.net/wenqiang1208/article/details/76244628https://blog.csdn.net/wenqiang1208/article/details/76244628https://blog.csdn.net/wenqiang1208/article/details/76244628

C++ 多态:func()函数 传入子类指针,形参是父类。

#include <iostream>
#include "stdio.h"
class parent {
public:
    virtual void test() {
        printf("11111\r\n");
    }
};
class child : public parent {
public:
    void test() override{
        printf("22222\r\n");
    }
};
 
void func(parent* xx) {
    xx->test();
};
 
int main() {
    child* ch = new child();
    func(ch);
}

C语言实现C++的多态:

比较核心的点:

  • 两个结构体之间的强制转换,以及转换后对方法的调用。
  • 通过在结构体A嵌套结构体B,实现A继承B
// main.c

#include "stdio.h"
#include <stdlib.h>

typedef void (*Func)();

void BaseFunc()
{
    printf("Base\r\n");
}

void DrivedFunc()
{
    printf("Drived\r\n");
}

typedef struct BASE
{
    Func func;
}Base;

typedef struct DRIVED
{
    Base base; //结构体嵌套--代表C++的继承
}Drived;

int main() 
{

    Base base;
    base.func = BaseFunc;
    base.func();

    Drived derive;

    derive.base.func = DrivedFunc;
    derive.base.func();

    Base *bb = &base;
    bb->func();

    bb = (Base*)(&derive);
    bb->func();
}

bb = (Base*)(&derive); 这里相当于是在C++中子类(derived类)的方法指向父类(Base类),也就是子类指向父类指针。

但是C语言中的多态其实是很不安全的!!!!!!

如果把DERIVED结构体改为这样

typedef struct DRIVED
{
    int a;
    Base base;  //结构体嵌套--代表C++的继承
}Drived;

再次运行之前的代码:程序会出现段错误。然后就说明这种转换bb = (Base*)(&derive) 是有问题的,于是做了如下修改。

// main.c

#include "stdio.h"
#include <stdlib.h>

typedef void (*Func)();

void BaseFunc()
{
    printf("Base\r\n");
}

void DrivedFunc()
{
    printf("Drived\r\n");
}

typedef struct BASE
{
    Func func;
    int b;
} Base;

typedef struct DRIVED
{
    int a;
    Base base;  //结构体嵌套--代表C++的继承
}Drived;

int main() 
{

    Base base;
    base.func = BaseFunc;
    base.func();

    Drived derive;

    derive.base.func = DrivedFunc;
    derive.base.func();
    printf("derive addr = 0x%x\r\n", &derive);
    printf("derive val  = 0x%x\r\n", &((&derive)->a));
    printf("derive bas  = 0x%x\r\n", &((&derive)->base));

    printf("=============================\r\n");

    Base *bb = &base;
    bb = (Base*)(&derive);

    printf("addr = 0x%x\r\n", &derive);
    printf("func = 0x%x\r\n", &bb->func);
    printf("val  = 0x%x\r\n", &bb->b);
}

结果如下:

Base
Drived
derive addr = 0xfddbeae0  // derive的地址
derive val  = 0xfddbeae0   // derive的val地址
derive bas  = 0xfddbeae8 // derive的base地址
=============================
addr = 0xfddbeae0  // bb的地址
func = 0xfddbeae0  // bb的func地址
val = 0xfddbeae8  // bb的val地址

扫描二维码关注公众号,回复: 13513326 查看本文章

根据打印,可以看出derive转为bb前后,0xffbeae0这片地址本身存放的内容是没有任何变化的,但是由于    bb = (Base*)(&derive); 等于把derive这片地址的内容按照Base结构体的定义去解释。

出现上述的段错误原因就是:0xfddbeae0-0xfddbeae8本身存放的是derive类的int a; 而转换之后把它当作Base类的Func func去解释了。所以要避免上述错误:必须把父类,也就是Base base;放在Derive类的最上面,这样才能保证内存对齐。

 所谓的C语言多态本质就是两个结构体的互相转换。

结构体的方法调用,是根据这个结构体内这个方法在结构体内的偏移量来调用的,而通过强转后,说白了DERIVED*偏移为0的内存解释数据和Base*偏移为0的内存解释是否能匹配,如果可以匹配,那么实现了所谓的多态,所以Base类和Derived类的重载的方法必须放在最前面,这样才能保证多态的效果!!!而这种错误在编译不会有问题,在运行会有问题,所以指针的强大和不安全这里有那么点感觉了。

猜你喜欢

转载自blog.csdn.net/m0_37844072/article/details/121163203
今日推荐