zoukankan      html  css  js  c++  java
  • C 语言实现 C++ 多态

    C 还是 C++?

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

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

    C 如何实现多态

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

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

    struct Animal
    {
         void (*move)();
    };

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

    void Animal_move()
    {
         printf("Animal move.\n");
    }

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

    struct Rabbit
    {
         void (*move)();
    };

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

    void Rabbit_move()
    {
         printf("Rabbit move.\n");
    }

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

         Animal *panimal;
         Rabbit rabbit;
    
         //...
    
         panimal = (Animal*)&rabbit;

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

    int main(void)
    {
         Animal *panimal;
    
         Rabbit rabbit;
    
         rabbit.move=Rabbit_move;
    
         panimal = (Animal*)&rabbit;
    
         panimal->move();
    }

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

    C 多态有什么问题

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

    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。

    捣乱 2013-05-09

    http://daoluan.net

    更多请访问:http://daoluan.net
  • 相关阅读:
    练习二(米奇老鼠)
    Photoshop笔记一
    HTML笔记1
    用IDEA写出第一个java web
    TCP协议怎么关闭?
    Sql Server2008R2与IDEA的连接
    通过HttpServer向Prometheus暴露端点
    了解Prometheus到底是什么?
    SPI扩展机制在框架中的使用
    motan系列1——与spring的集成原理
  • 原文地址:https://www.cnblogs.com/daoluanxiaozi/p/3069485.html
Copyright © 2011-2022 走看看