编译时的多态性:编译时的多态性是通过重载函数来实现的。
运行时的多态性:运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C++中,运行时的多态性通过虚成员实现。
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地址
根据打印,可以看出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类的重载的方法必须放在最前面,这样才能保证多态的效果!!!而这种错误在编译不会有问题,在运行会有问题,所以指针的强大和不安全这里有那么点感觉了。