以下的内容综合了多篇文章,加上一点自己的理解而成。目的为了给自己阅读他们文章后做一个笔记。在末尾给出了这些文章的地址。

多态的实现可以采用以下几种方式:
    (1)使用 vod * (万能指针)来实现“编译时多态”。
    (2)使用函数指针来实现“运行时多态”。
    (3)使用型如struct struct_name{

...............................
              char temp[0]; //或者char *temp;
          };
这种形式。

对于(1)举例如下:

void HandleMsg(unsinged int id, void *p)
{
    Msg1 *p1;
    Msg2 *p2;

switch(id)
    {
    case key1:
        p1 = (Msg1*)p;
        //do something
        break;
    case key2:
        p2 = (Msg2*)p;
        //do something
        break;
    default:
        break;
    }
}

这个例子也许不能说明函数的编译时多态,因为没有使用函数指针与vod * 之间转换来转换去。没有举这类例子,是因为想避免这种用法。
    对于(2)举例如下:
#ifndef C_Class
       #define C_Class struct
#endif

C_Class A {

C_Class A *A_this;
       void (*Foo)(C_Class A *A_this);
       int a;

int b;

};

C_Class B{               //B继承了A

C_Class B *B_this;  //顺序很重要
       void (*Foo)(C_Class B *Bthis); //虚函数
       int a;
       int b;
       int c;
};

void B_F2(C_Class B *Bthis)
{
       printf("It is B_Fun/n");
}

void A_Foo(C_Class A *Athis)
{

printf("It is A.a=%d/n",Athis->a);//或者这里
}

void B_Foo(C_Class B *Bthis)
{
    printf("It is B.c=%d/n",Bthis->c);
}

void A_Creat(struct A* p)
{
   p->Foo=A_Foo;
   p->a=1;
   p->b=2;
   p->A_this=p;
}

void B_Creat(struct B* p)
{
   p->Foo=B_Foo;
   p->a=11;
   p->b=12;   
   p->c=13;
   p->B_this=p;

}

int main(int argc, char* argv[])
{

C_Class A *ma,a;
       C_Class B *mb,b;

A_Creat(&a);//实例化
       B_Creat(&b);

mb=&b;
       ma=&a;

ma=(C_Class A*)mb;//引入多态指针

printf("%d/n",ma->a);//可惜的就是 函数变量没有private

ma->Foo(ma);//多态
       a.Foo(&a);//不是多态了
       B_F2(&b);//成员函数,因为效率问题不使用函数指针
       return 0;
}

在C中实现继承。
    对于例(1)中,有个重大的缺点,那就是缺乏类型安全。那么下面就可以使用继承来实现保证类型安全。

typedef struct tagT_MsgHeader {
    int id;
    //...
}MsgHeader;

typedef struct tagT_Msg1 {
    MsgHeader           h;
    int                 a;
    int                 b;
}Msg1;

typedef struct tagT_Msg2 {
    MsgHeader h;
    int       c;
    int       d;
}Msg2;

然后再重新定义消息处理函数:

void HandleMsg(MsgHeader *ph)
{
    Msg1 *p1;
    Msg2 *p2;

switch(ph->id)
    {
    case key1:
        p1 = (Msg1*)(ph);
        //do something
        break;
    case key2:
        p2 = (Msg2*)ph;
        //do something
        break;
    default:
        break;
    }
}

通过继承保证了类型安全,但是为了保证继承后的结构体灵活性,继承的变量MsgHeader h不能作为第一个成员变量,那么p1 =

(Msg1*)(ph)这种强制转换就无法得到正确的p1的地址,不过通过定义一个宏来实现这个:

#define CONTAINING_RECORD(address, type, field) ((type *)( /
                                                  (PCHAR)(address) - /
                                                  (UINT_PTR)(&((type *)0)->field)))
    这个类似的宏定义在linux中最常见。这样传入的MsgHeader 的指针经过宏处理,无论MsgHeader h在结构体的那个位置,均能获得继承后的结构体的首地址,这样再来强制转换就没有问题了。

顺便解释一下这个宏:
    #define CONTAINING_RECORD(address, type, field) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

先看&((type *)0)->field,它把“0”强制转化为指针类型,则该指针指向“0”(数据段基址)。因为指针是“type *”型的,所以可取到以“0”为基地址的一个type型变量field域的地址,这个地址也就等于field域到结构体基地址的偏移字节数。当前地址减去偏移地址便得出该结构体的地址。转换为(type *)型的指针。

在c中实现纯虚类,可以通过在结构体使用函数指针成员来实现。

//------------------结构体中的函数指针类似于声明子类中必须实现的虚函数-------------
typedef struct
 {
  void  (*Foo1)();
  char  (*Foo2)();
  char*  (*Foo3)(char* st);
 }MyVirtualInterface;
//---------------------------------------------------------------------------------

//------------------类似于纯虚类的定义---------------------------------------------
 MyVirtualInterface* m_pInterface;
 
 DoMyAct_SetInterface(MyVirtualInterface* pInterface)
 {
  m_pInterface= pInterface;
 }

void oMyAct_Do()
 {
  if(m_pInterface == NULL) return;
  m_pInterface->Foo1();
  c = m_pInterface->Foo2();
 }
//---------------------------------------------------------------------------------

//--------------------------子类一-------------------------------------------------
MyVirtualInterface  st[MAX];

//接着定义一些需要实现的函数 Act1_Foo1,Act1_Foo2,Act1_Foo3

MyVirtualInterface* Act1_CreatInterface()
{
 index = FindValid() //对象池或者使用Malloc!应该留在外面申请,实例化
 if(index == -1) return NULL;
 st[index].Foo1 = Act1_Foo1; // Act1_Foo1要在下面具体实现
 st[index].Foo2 = Act1_Foo2;
 st[index].Foo3 = Act1_Foo3;
 Return &st[index];
}
//-----------------------------------------------------------------------------------

//--------------------------主函数---------------------------------------------------
if((p = Act1_CreatInterface()) != NULL)
{
 List_AddObject(&List, p); //Add All
 While(p = List_GetObject())
 {
  DoMyAct_SetInterface(p);//使用Interface代替了原来大篇幅的Switch Case
  DoMyAct_Do();//不要理会具体的什么样的动作,just do it
    }
}
//-----------------------------------------------------------------------------------

如果父类不为纯虚类的类,那么在子类中通过宏来实现虚函数

MyVirtualInterface* ActByOther1_CreatInterface()
{
 index = FindValid() //对象池或者使用Malloc
 if(index == -1) return NULL;
 St[index].Foo1 = ActByOther1_Foo1; // Act1_Foo1要在下面具体实现
 St[index].Foo2 = ActByOther1_Foo2; //父类中已经实现了的
 St[index].Foo3 = ActByOther1_Foo3; //父类中已经实现了的
 Return &st [index];
}

#define ActByOther1_Foo1 Act1_Foo1  //这就是继承
ActByOther1_DoByOther() {}   //当然就可以添加新的实现

引用:

[1]http://blog.csdn.net/baoxingbo/articles/56406.aspx

[2]http://hi.baidu.com/blue_never_died/blog/item/b05f242d389bb734349bf7dd.html

关于C语言中继承和多态的实现相关推荐

  1. python中继承和多态

    继承和多态 继承 引入继承 我们有这样一个需求 模仿英雄联盟定义两个英雄类1.英雄要有昵称.攻击力.生命值属性2.实例化出两个英雄对象3.英雄之间可以互殴,被殴打的一方掉血,血量小于0则判断为死亡 那 ...

  2. java中继承和多态的实验,Java中的继承和多态

    我有两个类:Triangle和RightAngledTr. RightAngledTr继承自Triangle.代码如下: 三角类: class Triangle { public void draw( ...

  3. c语言中继承的好处,c语言中,继承和和组合有什么区别

    咨询我 400-64365-60 (咨询请说明来自律图) 地区:湖北- 缺点,继承和组合都是代码复用的有效方法.组合是将其他类的对象作为成员使用,子类也不得不会随之更改.更复杂的功能.优点.子类与父类 ...

  4. Java实验3继承、多态

    继承.多态(接口和包) 实验目的 (1) 掌握Java语言中继承和多态的相关概念 (2) 掌握Java程序设计中继承和多态机制的使用 (3) 掌握Java语言中接口和包的概念及使用 实验内容及要求 仿 ...

  5. c语言编程继承例子,C语言模拟实现C++的继承与多态示例

    一.面向过程编程与面向对象编程的区别 众所周知,C语言是一种典型的面向过程编程语言,而C++确实在它的基础上改进的一款面向对象编程语言,那么,面向过程与面向对象到底有什么样的区别呢? [从设计方法角度 ...

  6. Python中的继承和多态

    本文以生活中的基础现象为切入点,主要介绍了Python基础中继承和多态,包括单继承.多继承的语法.多态常见的 "鸭子类型". 以及如何重写父类的方法都做了详细的讲解. 一.继承的介 ...

  7. java实验报告4继承与多态_Java继承与多态实验报告

    西 西 安 安 邮 邮 电 大 学 (计算机学院) 课内实验报告 实验名称: : 态 继承与多态 ﻩ ﻩ 专业名称: 计算机科学与技术 班 班 级: 计科 1405 班 学生姓名: 高宏伟 学 学 号 ...

  8. java继承和多态的实验报告_Java继承与多态实验报告.doc

    Java继承与多态实验报告 西 安 邮 电 大 学 (计算机学院) 课内实验报告 实验名称: 继承与多态 专业名称: 计算机科学与技术 班 级: 计科1405班 学生姓名: 高宏伟 学 号: 指导教师 ...

  9. 详解C语言中头文件的作用

    大家好,先做个自我介绍,我是天蓬,欢迎阅读本篇博文. 由于本人理解能力不是很好,阅读他人文章时,常常看得晕头晕脑,这让我很是头疼,我想,世界上一定还有和我一样的人(哈哈,不是说你么笨哦).所以,我将会 ...

最新文章

  1. 每天AI资讯这么多,该看哪些?推荐一份优质AI内参!
  2. 搭建集群时的问题总结
  3. C++中使用TCP传文件
  4. C++ 版本ORM访问数据库之ODB访问oracle的Demo(三)
  5. innodb是如何存数据的?yyds
  6. 获得磁盘的C++描述信息
  7. 如果你产品的卖点跟竞争对手一样,那你怎么脱颖而出?
  8. Spring Boot中文文档
  9. react中创建组件
  10. 十七款PDF在线处理转换器,目前最全合集
  11. REST服务和RESTful API是什么
  12. 牛顿插值java_java实现牛顿插值法
  13. idea java maven 打包,idea maven项目 基于idea自己打包方式 以及使用maven插件打包的三种方式...
  14. 增长率用计算机怎么算,操作方法:Excel使用公式来计算增长率教程
  15. 学会jQuery 不用买书
  16. 硬件工程师常用的电路基础公式+换算!
  17. GDC2015分享:巫师3开放世界性能优化
  18. 关于用鲁大师对显卡性能进行评测时抛出“评测中切换页面”的异常的解决方案。
  19. 组策略应用:软件分配及软件发布
  20. 企业发展理论(二):偶然性理论

热门文章

  1. 【转】Magento2 数据库操作
  2. 第五节:Task构造函数之TaskCreationOptions枚举处理父子线程之间的关系。
  3. 需求分析之UML用例图学习
  4. 14工厂方法模式(Factory Method)
  5. 结合vue、react、angular谈谈MVC、MVP、MVVM框架
  6. bootstraptable treeGrid 懒加载_Java类加载机制及自定义加载器
  7. 【CodeForces - 485C】Bits (二进制相关,数学,贪心)
  8. 【HihoCoder - 1550】顺序三元组(思维)
  9. Mac安装mysql8.x最简洁的步骤,避免采坑
  10. JS正则表达式常见场景下的用法总结