關於C語言中繼承和多態的實現

來源:互聯網
上載者:User

    以下的內容綜合了多篇文章,加上一點自己的理解而成。目的為了給自己閱讀他們文章後做一個筆記。在末尾給出了這些文章的地址。

    多態的實現可以採用以下幾種方式:
    (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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.