您的位置:首页 > 编程语言 > C语言/C++

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

2012-03-22 10:27 344 查看
以下的内容综合了多篇文章,加上一点自己的理解而成。目的为了给自己阅读他们文章后做一个笔记。在末尾给出了这些文章的地址。
    多态的实现可以采用以下几种方式:

    (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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息