2014年12月20日 星期六

徹底了解Java新物件宣告(用C)

Dog dog = new Dog();
首先,大家腦中的第一個問題應該是 new Dog 後面的 () 吧!
為什麼 Dog 明明是個 class,後面還可以加小括號?
讓我們用 C 來看:

/*
 *宣告整數 i
 */
 int i;

/*
 * 宣告整數 i 並賦值
 */
int i = 0;

以上應該很好了解,那讓我們用相同的概念來看看這些程式碼:

/*
 * 這是我的 Dog
 */
typedef struct Dog {
    char *name;
    int height;
    int weight;
    int (* bark)(int times);
} Dog;

/*
 * 宣告 Dog 型態的物件
 */
Dog dog;

/*
 * 宣告 Dog 型態的物件並賦值
 */

int bark(int times) {
    int a;
    for(a = 0; a < times; a++) {
         printf("Woof!!!");
    }
    printf("\n");
    return 0;
}

Dog dog = {
    .name = "John",
    .height = 40,
    .weight = 9,
    .bark = &bark
};

這樣就完成一隻 Dog 了
可是每宣告了一個新物件就要做一次設定不是很麻煩嗎?
我們需要宣告一個幫助我們做設定的函式
你可能會想要這麼做:

Setup(dog);

但是這麼做你必須傳址進去才是正確的

Setup(&dog);

或是你想到了另一個方法,寫一個 setupDog() 函式,負責回傳一隻設定好的狗,像這樣:

Dog setupDog(void) {
    int bark(int times) {
        int a;
        for(a = 0; a < times; a++) {
             printf("Woof!!!");
        }
        printf("\n");
    return 0;
    };
    Dog d = {
        .height = 40,
        .weight = 9,
        .bark = &bark
    };
    return d;
}

接著,你可以這樣設定你的狗:

Dog dog = Setupdog();

如果要更像 Java 一點:

#define new
#define Dog() setupDog()

Dog dog = new Dog();

這下,Dog 後面的小括號意義應該就很明顯了,我們可以這樣用它:

#define new
#define Dog(a, b, c) setupDog(a, b, c)

Dog setupDog(int height, int weight, char *name) {
    int bark(int times) {
        int a;
        for(a = 0; a < times; a++) {
            printf("Woof!!!");
        }
        printf("\n");
    return 0;
    };
    Dog d = {
        .name = name,
        .height = height,
        .weight = weight,
        .bark = &bark
    };
    return d;
}

Dog dog = new Dog(40, 9, "John");


綜合以上所述,Dog dog = new Dog() 陳述式可以被這樣分解:

Dog dog    //宣告沒有值的空物件
new Dog()    //它會回傳設定好的值
dog = new Dog()    //把回傳的值賦予空物件

再來你就知道要怎麼用這隻狗了

int main(int argc, char *argv[]) {
    Dog john = new Dog(20, 5, "John");
    john.bark(2);
    printf("HI!!! I am %s\n", dog.name);
    john.bark(3);
}

輸出:
Woof!!!Woof!!!
HI!!! I am John
Woof!!!Woof!!!Woof!!!


文完