⓪著作 :蕭沖


我常用低階的語言觀點來看高階語言,我覺得那樣可以更深入的了解使用法方,堪至可以模擬出是如何實做的,可能遇到的問題。能想像Bjarne Stroustrup這個創造人當初可能是怎麼想的嗎?

這篇文章最主要的目的是要解釋為何需要用this指標?

前言:想像一下在沒有class之前,C語言程式設計師是如何達成近class模組化功能? 曾看過一些使用C開發的遊戲程式,裡面總定義了一堆的struct,當然還有一堆和這struct有關的function。在cpp裡struct和class是同樣的,都可以定義資料成員(data member)、成員函式(member function/method),僅差別在struct預設成員是public。然而在C語言裡,struct是不能有成員函式定義的,也因此C程式人員可能獨立的把方法寫在Global區塊上,是否可能模擬出把方法也嵌入struct中呢? 這樣就很像class了…請看以下我寫的演示範本:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef
struct StudentInfo
{
char *mName;
int mAgeInAc;
int mAgeInTw;
void (*mpCalc)(struct StudentInfo *self);
int (*mpGetTwAge)(struct StudentInfo *slef);
void (*mCopy)(struct StudentInfo *slef,
struct StudentInfo *src);

}STI;

/* 私人的方法 */
void ac_to_tw(STI *self)
{
self->mAgeInTw = self->mAgeInAc - 1911;
}

/*公開的方法*/
int get_tw_age(STI *self)
{
self->mpCalc(self);
return self->mAgeInTw;
}

/*公開的方法*/
void copy(STI *self, STI *src)
{
*self = *src;
}

/*建構子*/
STI create_sti_object(void)
{
STI object;
object.mName = 0;
object.mpCalc = ac_to_tw;
object.mpGetTwAge = get_tw_age;
object.mCopy = copy;
return object;
}

/*動態建構子*/
STI *p_create_sti_object(void)
{
STI *p_object = (STI *) calloc(1,sizeof(STI));
p_object->mName = 0;
p_object->mpCalc = ac_to_tw;
p_object->mpGetTwAge = get_tw_age;
p_object->mCopy = copy;
return p_object;
}

/*動態解構子*/
void destroy_sti_object(STI *self)
{
free(self);
}

#pragma argsused
int main(int argc, char* argv[])
{
int my_tw_age;
STI student_info;
STI *p_student_info;
STI my_info;
STI babe_info;
STI copy_info;

/*沒有建構式的建立法*/
student_info.mName = "蕭一世";
student_info.mAgeInAc = 1951;
student_info.mpCalc = ac_to_tw;
student_info.mpCalc(&student_info);
printf("%s 民國%d年生\n",student_info.mName,student_info.mAgeInTw);

/*使用動態建構方式,且直接呼叫私人方法*/
p_student_info = p_create_sti_object();
p_student_info->mName = "蕭二世";
p_student_info->mAgeInAc = 1961;
p_student_info->mpCalc(p_student_info);
printf("%s 民國%d年生\n",p_student_info->mName,p_student_info->mAgeInTw);
destroy_sti_object(p_student_info);

/*使用建構子,且呼叫公開方法取回值,Instance1 */
my_info = create_sti_object();
my_info.mName = "蕭沖";
my_info.mAgeInAc = 1971;
my_tw_age = my_info.mpGetTwAge(&my_info);
printf("%s 民國%d年生\n",my_info.mName,my_tw_age);

/*使用建構子,且呼叫公開方法取回值,Instance2A */
babe_info = create_sti_object();
babe_info.mName = "寶貝";
babe_info.mAgeInAc = 1976;
my_tw_age = babe_info.mpGetTwAge(&babe_info);
printf("%s 民國%d年生\n",babe_info.mName,my_tw_age);

/*使用拷備函式,Instance2B */
copy_info = create_sti_object();
copy_info.mCopy(& copy_info, &babe_info);
copy_info.mName = "寶貝拷備";
copy_info.mAgeInAc = copy_info.mAgeInAc + 7;
my_tw_age = copy_info.mpGetTwAge(& copy_info);
printf("%s 民國%d年生\n",copy_info.mName,my_tw_age);

system("pause");

return 0;
}


我們使用了函式指標來實作「方法」的部份。值得注意的部份是:從這裡我們可以看出方法的部份是共享的,僅資料的部份是各自不同(參考最後二個instance)。使用建構式是為了要把方法與Global下的function連結起來,這也是cpp中的一個新觀念-「建構子」。但在這裡還沒有實作出public與private的限制,也就是data hiding的部份。上面的方法中,都有一個參數STI *self這就是為何cpp中的method需要*this的原因了!只是cpp中把這個參數給隱藏起來,在complie時在偷偷的插入這個pointer到最前面的參數,並在method中關於data member和member function的部份加上this->,就如同上面的範例使用了self->。這樣就可以達成「Instance的方法共享,資料私有」。free後method的部份依舊存在。僅data被free了!

範例子寫了一個copy method,演示了cpp中何時你可能會把this這個關鍵字用出來,當實作copy時,你就要自己寫入 *this 這就不是compiler會幫你的了! 還有另一個可能會用到的時候: 傳回物件的reference時return *this,不過這是在reference type 是cpp裡才有的。
創作者介紹
創作者 aftcast 的頭像
aftcast

蕭沖的書房

aftcast 發表在 痞客邦 留言(1) 人氣()


留言列表 (1)

發表留言
  • hi
  • enclosing scopes

    class 或 struct 在 C++ 中已經不是 C 中所視為是一種自定資料型態,
    在 C++ 中 class/struct 視為是一種圈封作用域(enclosing scopes)
    如同 namespace.

    ex:
    struct Foo
    {
    int var;
    }foo;

    int main()
    {
    foo.var = 0; //一般使用方式, var 前無任何修飾表示從當前繼承體
    //系直接作搜尋, 找到的 var 位於 ::Foo 內.
    foo.::Foo::var = 0; //var 受到修飾.
    }

    ::Foo::var 表明了從 global namespace(::) 下的 namespace Foo
    找 var 成員, 此 var 成員視為是一種全域性的變數, 只是它的使用受限於
    2 個條件:

    1.若不是有 static 修飾, 必須由物件的 -> 或 . 運算子來存取使用
    2.受到 public/protected/private 修飾的影響