C 语言实现 C++ 多态

C 还是 C++?

C++ 中的多态是指「通过基类对象的指针或者基类对象的引用调用虚函数」,表现更多派生类的特性,但根据 C++ 多态的实现,我们发现这种方法存在一定的空间和效率的折损。不可否认,多态轻松解决了很多工程中遇到的问题,这与 pure C 的解决方法比起来,更为优雅。

在考虑移植性上,C 的光芒要盖过 C++,但 C++ 的多态是可借鉴的,于是用 pure C 来模仿 C++ 中多态行为。

C 如何实现多态

在 C 中没有类的概念,但有 struct,而且 C 中的 struct 是不允许有函数的,只允许存在变量,那是不是函数变量就允许存在了?!所以,函数指针可以给我们一些提示。

假定有一个结构体 struct Animal 声明如下:

?
1
2
3
4
struct  Animal
{
      void  (*move)();
};

此时 Animal 中的 move 只是一个指针,并没有赋值,也就是说它不能代表任何的行为,但我们可以在 main 函数中对其进行赋值,赋予相应的行为。

?
1
2
3
4
void  Animal_move()
{
      printf ( "Animal move.\n" );
}

再假定一个结构体 struct Rabbit,我们可以暂且把它看作(因为 C 中没有继承概念)struct Animal 的派生类,声明如下:

?
1
2
3
4
struct  Rabbit
{
      void  (*move)();
};

同样我们可以给 Rabbit 的 move 预定义一个行为:

?
1
2
3
4
void  Rabbit_move()
{
      printf ( "Rabbit move.\n" );
}

struct Animal 和 struct Rabbit 在内容上完全一致,而且变量对齐上也完全一致,可以通过将 struct Rabbit 类型的指针强制转换为 struct Animal 类型的指针,即:

?
1
2
3
4
5
6
Animal *panimal;
Rabbit rabbit;
 
//...
 
panimal = (Animal*)&rabbit;

这样,我们就可以通过 struct Animal 类型的指针或者引用来操纵 struct Rabbit 类型的对象了。

?
1
2
3
4
5
6
7
8
9
10
11
12
int  main( void )
{
      Animal *panimal;
 
      Rabbit rabbit;
 
      rabbit.move=Rabbit_move;
 
      panimal = (Animal*)&rabbit;
 
      panimal->move();
}

Rabbit move.
请按任意键继续. . .

C 多态有什么问题

是不是有需要注意的问题?为什么刚才特别提出「在内容上完全一致,而且变量对齐上也完全一致」?倘若把 struct Animal 的声明作稍微的改变:

?
1
2
3
4
5
struct  Animal
{
      int  age;
      void  (*move)();
};

运行崩溃了,并不能得到上面的执行结果,原因是 move 函数指针 在struct Animal 中和 struct Rabbit 中的偏移量不同,结构体是根据变量在结构体的偏移量来读取或者修改变量的。当执行 panimal->move(); 的时候,实际上引用了非法的地址:

panimal->move();

可以被形象的转化为:

( * (panimal+sizeof(age)) ) ();

但发现 panimal 是指向 struct Rabbit 实体的,panimal+sizeof(age) 已经指向了非法地址:

struct Rabbit 结构 调用
void (*move )(); <------ rabbit.move();
非法地址 <------ panimal->move();

因此需要模拟多态,必须保持函数指针变量对齐

在一些 c 开源项目中经常用到这种设计,譬如 libevent。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值