以下的内容综合了多篇文章,加上一点自己的理解而成。目的为了给自己阅读他们文章后做一个笔记。在末尾给出了这些文章的地址。
多态的实现可以采用以下几种方式:
(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++, Smalltalk, 或者Java。 本文从较底层的视角用面向过程的语言(比如C)对面向对象予以实现,这对于一些想运用...
使用C语言实现封装,继承,多态等面向对象的特性使用C语言实现封装,继承,多态等面向对象的特性使用C语言实现封装,继承,多态等面向对象的特性使用C语言实现封装,继承,多态等面向对象的特性使用C语言实现封装,...
C语言:多态(单继承实现)源码
用C语言实现 C++封装、继承、多态,网络上的资源,我们一起感谢未留名的前辈。
Java语言程序设计ppt第十一章(继承和多态)
本篇文章主要介绍了C语言模式实现C++继承和多态的实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
C语言:多态(多继承实现)
本文主要给大家简单讲诉了C和C++的区别以及如何使用C语言模拟实现C++继承和多态,并附上示例代码,是篇相当不错的文章,推荐给喜欢C语言的小伙伴们
用C语言模拟了 c++ 封装、继承、多态三大特性。
BREW接口的继承和多态.pdf 一篇深入理解brew接口关联关系的文档 对于c语言的学习人员也非常有用
本篇文章主要介绍了C语言模拟实现C++的继承与多态示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
C语言实现类的封装、继承和多态,基类、派生类、结构体实现类
C 程序设计课件:第八章 继承与多态.ppt
C++是C语言的继承,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。C++擅长面向对象程序设计的同时,还可以进行基于...
C语言下实现面向对象的三大特性:封装、继承、多态。注意:此文件是vs2010下的工程文件
9.1来自C语言中的静态成员 9.1.1函数内部的静态变量 9.1.2控制连接 9.1.3其他的存储类型指定符 9.2名字空间 9.2.1产生一个名字空间 9.2.2使用名字空间 9.3C++中的静态成员 9.3.1定义静态数据成员的存储 9.3.2嵌套...
C++多继承多态的实现 如果一个类中存在虚函数,在声明类的对象时,编译器就会给该对象生成一个虚函数指针,该虚函数指针指向该类对应的虚函数表。 多态的实现是因为使用了一种动态绑定的机制,在编译期间不确定...
项目使用C语言实现, 但是借鉴了面向对象编程思想, 将一些方法和属性进行了封装, 并且实现了面向对象编程中"继承"和"多态"的特性C语言课程设计大作业—在Windows平台下开发的Fat32文件系统。项目被拆解成了多个层次,...
对于嵌入式Linux开发类职位来说,最重要的是C语言基本功底,对C语言要了解的十分透彻,比如C语言的面向对象编程,怎么用C语言去实现面向对象类高级语言的继承、多态、封装。达到熟练掌握数据结构,尤其是链表。对于...