2010/03/31

[C++] implicit constructor

如果我們在定義class時沒有明確的給定constructor與destructor時,就會compiler就會自動幫你定義一個沒有功能的constructor與destructor。比如下面的例子:

Ex1

class Base
{
public:
    // 沒有定義constructor,則有一個implicitly constructor叫做: Base(){}
};

class Derived: public Base
{
public:

// Derived的constructor沒有呼叫其parent的constructor ,但compiler會implicitly的呼叫Base(){}。而由於Base(){} 也已經被compiler implicitly的定義了,所以沒問題。

    Derived(int y)    {     }
};

 

但是如果我們已經明確地定義建構子(explicit constructor),則compiler就不會再次定義沒有功能的implicit constructor。比如下例:class Base已經有一個explicit constructor叫做 Base(int x) ,那麼沒有參數的constructor Base() 就不會被隱含地(implicitly )被宣告了。

Ex2

class Base
{
public:
    Base(int x)    { // 已經有explicit constructor,則不會有implicit constructor
    }
};

class Derived: public Base
{
public:

// 如果child class的constructor 沒有explicit 的呼叫parent的constructor,則compiler則會implicitly去呼叫其parent的implicit constructor,也就是沒有參數的constructor Base()。但是這個情況,Base()不會被宣告,所以會出現:「'Base' : 沒有適當的預設建構函式」的錯誤。

    Derived(int y)    { 
    }
};

 

解決方法之一:在child class的constructor去explicitly地呼叫parent已經定義好的constructor。

Ex3

class Base
{
public:
    Base(int x)    { // 已經有explicit constructor,則不會有implicit constructor
    }
};

class Derived: public Base
{
public:

    Derived(int y): Base(y)   { 
    }
};

 

解決方法之二:我們可以在parent class裡面explicitly去宣告一個沒有參數的constructor。

Ex4

class Base
{
public:

    Base(int x)    { // 已經有explicit constructor,則不會有implicit constructor
    }

    Base(){ }      // 因此我們主動宣告一個沒有參數的constructor

};

class Derived: public Base
{
public:

    Derived(int y):  {  // 這時候child 的constructor去implicitly的呼叫Base()就不會有錯誤了。
    }
};

2010/03/26

[C++] 使用Pointer to pointer或Reference to pointer,改變pointer的address

在C語言裡,我們可以使用pointer指向一個實體,因此如果把實體變數的address傳到一個funtion的pointer,那就可以改變此pointer所指向的實體的值。

但是如果我們要改變的不是pointer所指向的實體的值,而是pointer本身的值,那就把pointer當作一種type,再把它的address傳到funtion的double pointer。以下將舉一個例子說明。

假設我們有一個function readData可以從網路抓取packet後,填到一個unsigned型態的的buffer(以pointer傳入),接著我們會使用一個function parse1來分析前半段的buffer,然後在使用function parse2來分析後半段的buffer。在parse的程式碼中,我們使用(buffer++) 來移動buffer的pointer,以利往下讀取資料。

在下面的程式碼中,我們在parse1和parse2都是使用unsigned *buffer來接住main裡的buffer的位址(假設在0x100),因此parse1和parse2接收到的pointer的值都是副本,也就是0x100。所以即使在parse1移動buffer pointer,也不會影響在main的buffer的位址。所以,當parse2呼叫時,傳入buffer pointer的值,依然是0x100,還是從buffer的頭開始分析。

image

一個錯誤的例子

#include <iostream>
using namespace std;
#define BUFFER_SIZE 10

void readData(unsigned *buffer, int size) // Ex:從網路讀取資料寫道buffer
{
    for (int i = 0; i < size ; i++)    {
        buffer[i] = i;
    }   
}

void parse1(unsigned *buffer, int size) // 開始第一階段parse讀取到的資訊
{
    for (int i = 0; i < size ; i++)    {
        cout << "processing with parser1:" << *(buffer++) << endl; // 每讀取一個元素後,指標移動
    }   
}

void parse2(unsigned *buffer, int size) // 希望從第一階段的parse後,繼續第二階段的parse
{
    for (int i = 0; i < size ; i++)    {
        cout << "processing with parser2:" << *(buffer++) << endl;
    }   
}

int main(void)
{
    unsigned buffer[BUFFER_SIZE];
    readData(buffer, BUFFER_SIZE);
    parse1(buffer,BUFFER_SIZE/2);
    parse2(buffer,BUFFER_SIZE/2); // 此時buffer的pointer,並不會從一半開始,還是原本的頭開始
    return 0;
    /* output:
    processing with parser1:0
    processing with parser1:1
    processing with parser1:2
    processing with parser1:3
    processing with parser1:4
    processing with parser2:0
    processing with parser2:1
    processing with parser2:2
    processing with parser2:3
    processing with parser2:4

    */
  
}

 

我們可以使用pointer to pointer達到修改pointer的值的目的。方法如下:先使用 unsigned *p = buffer; 來複製一份buffer的address。因此p的值為0x100,並且假設p的address為0x500。然後在parse裡使用unsigned **buffer_p指向p,因使buffer_p的值為0x500。接著我們可以使用(*buffer_p)++來改變p的值,也就是p所指向的位置可以跟個改變。所以在parse1執行完後,p的值,就會改變成0x200,所以再把p的address給parse1後,buffer_p的值雖然一樣式0x500,但是buffer_p所指向的值就變成0x200。因此使用*((*buffer_p)++) 可以指向p,再指向buffer裡實體的unsigned變數

Note,由於array的address不可以改,所以我們才需要一個p來記錄buffer的address,並且透過修改p的值來達到移動pointer的目的。
  image

一個正確的例子(pointer to pointer)

#include <iostream>
using namespace std;
#define BUFFER_SIZE 10

void readData(unsigned *buffer, int size)
{
    for (int i = 0; i < size ; i++)    {
        buffer[i] = i;
    }   
}

void parse1(unsigned **buffer_p, int size)
{
    for (int i = 0; i < size ; i++)    {
        cout << "processing with parser1:" << *((*buffer_p)++) << endl;;
    }   
}

void parse2(unsigned **buffer_p, int size)
{
    for (int i = 0; i < size ; i++)    {
        cout << "processing with parser2:" << *((*buffer_p)++) << endl;;
    }   
}

int main(void)
{
    unsigned buffer[BUFFER_SIZE];
    unsigned *p = buffer;
    readData(buffer, BUFFER_SIZE);
    parse1(&p,BUFFER_SIZE/2);
    parse2(&p,BUFFER_SIZE/2);
    return 0; 
   /* output: 
    processing with parser1:0
    processing with parser1:1
    processing with parser1:2
    processing with parser1:3
    processing with parser1:4
    processing with parser2:5
    processing with parser2:6
    processing with parser2:7
    processing with parser2:8
    processing with parser2:9
    */

}

如果你覺得看不習慣pointer to pointer,可以使用reference to pointer也可以達到同樣目的。請先閱讀這篇:

[C++] Call by value、Call by pointer、Call by reference

一個正確的例子(reference to pointer)

#include <iostream>
using namespace std;
#define BUFFER_SIZE 10

void readData(unsigned *buffer, int size)
{
    for (int i = 0; i < size ; i++)    {
        buffer[i] = i;
    }   
}

void parse1(unsigned *&buffer, int size)
{
    for (int i = 0; i < size ; i++)    {
        cout << "processing with parser1:" << *(buffer++) << endl;;
    }   
}

void parse2(unsigned *&buffer, int size)
{
    for (int i = 0; i < size ; i++)    {
        cout << "processing with parser2:" << *(buffer++) << endl;;
    }   
}

int main(void)
{
    unsigned buffer[BUFFER_SIZE];
    unsigned *p = buffer;
    readData(buffer, BUFFER_SIZE);
    parse1(p,BUFFER_SIZE/2);
    parse2(p,BUFFER_SIZE/2);
    return 0;
/* output:
    processing with parser1:0
    processing with parser1:1
    processing with parser1:2
    processing with parser1:3
    processing with parser1:4
    processing with parser2:5
    processing with parser2:6
    processing with parser2:7
    processing with parser2:8
    processing with parser2:9
    */
}

2010/03/22

敢找哈佛吵架的台大團隊

敢找哈佛吵架的台大團隊【商業週刊1165期 製作人:孫秀惠 撰文者:李郁怡 】

這是一場沒有出國的「壯遊」!台大學生組成一百二十三人的跨校核心團隊,如何跟時間賽跑,激發團隊熱情,辦了一場規模空前的跨國會議?

三月十四日星期天晚上九點,由台灣大學與哈佛大學聯名舉辦的「世界模擬聯合國大會 WorldMUN2010」社交活動「世界博覽會(Global Village)」緊接在開幕式之後即將開場。約一千多名盛裝打扮的國際學生,湧進台北市政府市政大廳。

花十萬個工作小時 建立二百一十名成員的志工隊

市府後門廣場排出動線,一個人花不到兩秒鐘,這一千名的學生手裡拿著像是悠遊卡的「Super Card」(超級卡),「嗶」一聲,就完成入場;參加過在瑞士日內瓦、墨西哥等地舉辦的世界模擬聯合國大會代表們,高興的說,不必對名冊、不必排隊,等待時間整整縮短了三十分鐘。

「Super Card」將所有代表的身分識別資訊、在台的食衣住行需求,整合在台北悠遊卡上,只要其中一項資訊更動,台大團隊建置的後勤支援資訊就會一併更新。

一張小小的資訊卡,只不過是台大團隊這次的一項成績。為了讓世界模擬聯合國大會,連續五天的會議與社交活動,從開幕到閉幕,都能像第一晚的世界博覽會一般順暢,台大團隊在這次會議前已經花費一年,投入十萬個工作小時,除了一百二十三位跨校核心成員,再招募二百一十名來自全國各大專院校、高中的志願工作者組成志工團隊,八個部門總計完成四百三十份的企畫書、建構起組織分工與職掌,完成三百七十條SOP,寫下每一個主要活動以分鐘為計算單位的流程控制表。

每一個部門都像是一個縝密的企業,和時間賽跑般的運作著。

要說這群台灣囝仔辦聯合國的故事,得先由「簽證」談起。台大團隊向哈佛大學爭取主辦世界模聯大會已有十年,過去爭取不到,在於台灣的國際處境十分特殊,在許多國家並沒有設立辦事處,光是要來開會的代表辦簽證,就可能影響來台意願。

打通外交部關鍵人脈 一天敲定對各國代表發落地簽

在去年暑假,開始籌辦會議之初,台大團隊就開始與外交部交涉,爭取所有與會代表,包括巴基斯坦、委內瑞拉、黎巴嫩等國家在內的代表都可以有「落地簽證」的便利。

一開始,學生的要求石沉大海,兩個月後,台大團隊因為申請外交部經費補助,得到一次簡報機會,台大團隊的總召集人侯宗成,把握機會爭取:「荷蘭對所有參加代表都給免簽證待遇!」「這件事不做,影響(台灣)國際觀感!」

在場聆聽簡報的外交部單位主管意識到問題,這才馬上與領事局聯絡,懸宕兩個月的落地簽證,在一天之內敲定。

為了舉辦這場跨國盛會,台大團隊接洽的公家部門,從中央到地方,超過二十個,大從警力支援,小到場地租借,面對公務員的態度,從支持到冷漠「完全兩極化」,團隊碰釘子的經驗可說不勝枚舉。

「就像是租借場地好了,我們真的很感謝台北市政府觀光傳播局,在這之前三個月我們至少碰了二十次釘子,完全沒有進展,還有的單位一下子說檔期可以,一下子說:『我們什麼時候答應你了?』」文化活動部門部長,台大中文系三年級的蘇煒翔說道。

「我們學會要找到關鍵人脈!」「還有動作要快,一旦關鍵人脈同意幫忙打電話,當下就牽上下一個人脈,把事情搞定。」侯宗成表示。

為經費與哈佛辯論 預算一條一條談,遭嚴厲質疑打擊

如果說要辦成一個成功的大型跨國會議,對內的溝通協調已經夠難了,台大團隊另外一個要克服的困難,就是跨國團隊協同工作。

尤其是與哈佛團隊取得互信,台大團隊經歷了一場「跨文化溝通」震撼教育。

問題的開端,是「經費」。由於去年九月起到去年底之間,台大團隊向民間募款不順利,接觸過上百家的企業失敗之後,預算出現一千萬元的缺口。

因為財務問題,雙方的關係開始緊張。先是去年十月月底,一天凌晨,負責資金募集部門、台大政治系三年級的呂艾珊接到了哈佛團隊召集人,也是世界模擬聯合國會議秘書長Ami Nash寄來一封英文措辭嚴厲的信,質疑為什麼台灣團隊募不到款?信上還列出十幾種方法,懷疑台大團隊沒有試過使用這些方法與企業溝通。接著,在雙方的線上會議,又質疑為何台大團隊沒辦法爭取政府支持場地經費?

這種毫不客氣的溝通文化,對一向得到社會高度肯定的台大學生來說,簡直難以忍受。

由兩校召集人帶領相關財務部門主管,為了錢,展開一連串的跨國線上談判,也因為文化差異激盪出火花。

「就像是跨國企業母公司對子公司查核帳目一樣,」「對方直接拿出預算一條一條來談,哪些他們認為是有必要的,哪些沒有必要,要我們因應,而且口氣完全有話直說,沒有客氣寒暄,」財務部門部長、台大政治系三年級的虞雅惠感受到強烈的文化差異。

原來台大學生團隊非常樂觀,大多數人都懷著「要為台灣辦一場前所未有的國際會議」想法,第一版的預算書有許多創新服務,接駁巴士、客製化的觀光地圖,甚至想請雲門舞集來表演……,完全以辦好會議為考量,卻沒有想到每個構想就等同於一筆預算。進入與哈佛逐項談判,台大團隊感受到預算刪減的壓力,開始回頭要求提出活動計畫的主管,去向發包廠商比價;「結果,這才發現,很多同學以為砍不下價格來的事,比了幾家之後,的確有砍價空間。」

另一次的交鋒,是台大團隊為了想要讓活動具有台灣意象,堅持要以台北悠遊卡,結合會場識別與報名的功能,做成「Super Card」,在來自四十多國的學生代表之前,展現台灣高科技形象。哈佛團隊覺得,「傳統的紙本雖然麻煩,但成本是Super Card的五分之一,為什麼堅持一定要辦卡?」雙方就成本、應該各自支出的金額,多次像這樣在線上辯論攻防。

要辦史上最棒活動 總召被團隊逼出改變,學會授權

負責交通專案的台大國企系三年級生劉書晴與副部長蘇敬博,為說服哈佛,還做線上簡報、畫作業流程圖,說明可創造的效益,瘋狂投入程度被團隊封了個「Super Card Girl」(超級卡女孩)的綽號,也因為這樣才說服哈佛。

「我們要辦一場有史以來最棒的模聯活動!」這是台大團隊成員們最常提到的字眼。而過去這一年,為了完成這個夢想,這群年輕人在課業之外,每天投入平均五到六小時,籌辦會議,箇中的滋味,侯宗成最清楚。

這一年,這位電機系大四學生,從無到有建立一個全國的校際團隊,這一年,也是他經歷無數妥協、堅持與自我突破的一年。

二○○九年五月,當侯宗成站在台灣大學第二學生活動中心之前,接到了世界模擬聯合國活動哈佛團隊來的電話:「恭喜你們!台灣擊敗了其他國家,爭取到了主辦權。」他的快感只持續了一天,接著,他陷入了「我不知道從何做起」的焦慮,失眠了三個月。

侯宗成沒有留過學,小時候也不曾被送出國,流利的英文完全是在台灣本土造就;任教職的母親,透過大量的英聽培養他的語感,接著讓他上會話、再訓練他大量閱讀,累積英文字彙,讓他成為英文演講比賽的常勝軍。

偶然的機會,因為社團活動,他參加二○○七年在日內瓦舉行的世界模擬聯合國大會,與各國菁英學生聚集一堂,讓他受到很大的刺激。他還記得,當時他參加的是 WTO委員會,當主席要徵詢發言時,「唰」一聲,在場幾百隻手同時舉了起來;接下來各國學生代表之間的辯論、演講、攻防,他都插不進去,完全被「邊緣化」。

從日內瓦回來之後,他思考,要怎麼做,才有機會從邊緣到核心。

事隔一年,他再飛到墨西哥參加模聯,他開始懂得觀察,會場的每個小團體都有意見領袖,要仔細聆聽所有人發言之後,再關鍵性的發表意見,讓別人記得有你這號人物。

總是看到事情可以更好的人格特質,是他提升自己能力的動力,但回到領導、建構首次在台灣舉辦的世界模擬聯合國大會,卻成為他的考驗。

侯宗成形容自己很完美主義,他想到要將一個規模這麼大的活動辦成,一定要靠縝密的制度,於是要求核心幹部,針對所屬部門未來要達成的任務,寫出企畫書。

問題是,「我只聚焦於組織,卻無法信任。」侯宗成不諱言,在團隊形成初期,他所犯下的錯誤。

「那時我們真的很怕接到他的電話,」呂艾珊描述,各部門被侯宗成追著寫企畫書;而且「他還會乾脆指示第一點、第二點怎麼做,很多人就覺得,啊,那你來就好啦!」宗成的戰友、台大國企系三年級的楊涵茜不客氣的吐槽。

當時核心團隊為此激烈爭執,「最後,是因為他們不斷要求授權,我才學著放手的。」讓他直接面對的人,由十幾個減少到三個,授權的結果,組織反而動了起來。

「我的改變是被團隊逼出來的,很多時候,你要試著相信別人的善意,然後去試、去溝通,」他說,只有這樣最後才能協同合作。

如果去問台大團隊各部門的負責人,在這場規模盛大的跨國會議裡,學會了什麼關鍵能力,每個人的回答都不一樣!

在會議最後一刻,都還帶著團隊搶救因為文件沒有備齊、拿不到落地簽狀況的龔鵬驊回答你:那是團隊相互補位的默契;一天要接三十七通電話的公關部門主管、台大政治系三年級生鄭郁儒說,當好啦啦隊,才能當好領導人;經歷募款超不順利的呂艾珊,則從失敗中發現及早找到關鍵人脈的重要性……。「大人的世界,跟我們想得很不一樣!」負責志工招募訓練、台大經濟系三年級的王鼎鈞說。

一場完全由學生領導的跨國會議,就像是一個最夢幻的教室,它以最真實的方式,教會這群台灣社會未來領導人,讓夢想變成現實的關鍵能耐──人脈、溝通與領導,還有,從失敗中修正自己,獲得成長的勇氣。

[C++] string to int, int to string, string to double, double to string

Convert.h

#ifndef CONVERT_H_
#define CONVERT_H_
#include <sstream>
#include <string>
using namespace std;
class Convert{
public:
    static int str2int(const string &str);
    static string int2str(const int n);
    static double str2double(const string &str);
    static string double2str(const double n);
};
#endif /*CONVERT_H_*/


Convert.cpp

#include "Convert.h"
int Convert::str2int (const string &str) {
    int n;
    stringstream ss(str);   
    ss >> n;       
    return n;
};   
string Convert::int2str (const int n) {
    stringstream ss;
    ss << n;
    return ss.str();
}
double Convert::str2double(const string &str){
    double n;
    stringstream ss(str);   
    ss >> n;       
    return n;
}
string Convert::double2str(const double n){
    stringstream ss;
    ss << n;
    return ss.str();
}

2010/03/21

Dynamic Memory Allocation in C and C++ (malloc, new, and vector)

1. C version - one dimension array
#include <stdlib.h> // for malloc, realloc, free

#include

<stdio.h>

/*

void * malloc ( size_t size );

- Allocates a block of size bytes of memory, returning a pointer to the beginning of the block.

*/

/*

void free ( void * ptr );

- Deallocate space in memory previously allocated using a call to malloc,

- calloc or realloc is deallocated, making it available again for further allocations.

*/

/*

void * realloc ( void * ptr, size_t size );

- Reallocate memory block.

- The content of the memory block is preserved up to the lesser of the new and old sizes.

- If the new size is larger, the value of the newly allocated portion is indeterminate.

*/

int

main()

{

int size = 10;

// dynamically allocate a memory block with size x sizeof(int)

int *arr = (int*)malloc(size * sizeof(int)); // the same as (int*) calloc (size, sizeof(int));

printf("address of arr is %X\n",arr);

for (int i = 0; i < size ; i++){

arr[i] = 1; // Treat the memory block as a array

}

arr = (int*)realloc (arr ,2 * size * sizeof(int)); // Reallocate memory block

printf("address of arr is %X\n",arr);

for (int i = 0; i < 2*size ; i++){

printf("arr[%d]=%d\n",i,arr[i]); // arr[0~9] is 1. arr[10~19] is indeterminate.

}

free(arr); // Deallocate space

return 0;

}

2. C version - two dimension array - pointer to pointer
#include <stdlib.h>

#include

<stdio.h>

#include

<time.h>

/*

int **arr ----> |------|

                      | int* | ---> | int int |

                      | int* | ---> | int int |

                      | int* | ---> | int int |

                      |------|

                                           ||

                                           ||

                                           ||

                                          \/

                               m x n 2-D array

*/

int

main()

{

int m = 3 , n = 2; // m x n matrix

int **arr; // pointer to pointer (double pointer)

arr = (int**)malloc(m * sizeof(int*)); // sizeof(int*): the size of int pointer instead of int

for (int i = 0; i < m ; i++)

{

arr[i] = (int*)malloc(n * sizeof(int));

// arr[i] is the same as *(arr+i). Ex:

// *(arr+i) = (int*)malloc(n * sizeof(int));

}

srand(time(NULL));

for (int i = 0; i < m ; i++)

{

for (int j = 0; j < n ; j++)

{

arr[i][j] = rand()%10; // Treat double pointer as 2-D array

// *(*(arr+i)+j) = rand()%10;

printf("%d\t",arr[i][j]);

}

printf("\n");

}

// We should not forget to free the memory which we have allocated dynamically,

// starting from the lowest level. i.e, in the reverse order of allocations.

// If we free up the higher level pointers first the lower level pointers would be lost

// and we would not be able to free up the memory allocated to those pointers.

// This would lead to memory leaks. Given below is how we should free up the memory.

for (int i = 0; i < m ; i++){

free(arr[i]);

}

free(arr);

return 0;

}

3. C++ version - one dimension array
#include <cstdlib>

#include

<cstdio>

#include

<iostream>

using

namespace std;

// Type *array = new Type(size);

// delete array;

int

main()

{

int size = 10;

int *arr = new int[size]; // array with size = 10

int *p = new int(5); // a int with parameter 5. That is, *p is 5.

for (int i = 0; i < size ; i++){

arr[i] = 1; // Treat the memory block as a array

}

/*

Reallocate.

- In contrast to C's realloc, it is not possible to directly reallocate memory allocated with new[].

- To extend or reduce the size of a block, one must allocate a new block of adequate size,

- copy over the old memory, and delete the old block.

- The C++ standard library provides a dynamic array that can be extended or reduced in its std::vector template.

*/

delete[] arr; // Arrays allocated with new[] must be deallocated with delete[].

delete p;

return 0;

}

4. C++ version - two dimension array - pointer to pointer
#include <cstdlib>

#include

<cstdio>

#include

<ctime>

#include

<iostream>

using

namespace std;

/*

int **arr ----> |------|

                      | int* | ---> | int int |

                      | int* | ---> | int int |

                      | int* | ---> | int int |

                      |------|

                                           ||

                                           ||

                                           ||

                                          \/

                               m x n 2-D array

*/

int

main()

{

int m = 3 , n = 2;

int **arr;

arr = new int*[m];

for (int i = 0; i < m ; i++){

arr[i] = new int[n];

}

srand(time(NULL));

for (int i = 0; i < m ; i++)

{

for (int j = 0; j < n ; j++){

arr[i][j] = rand()%10;

cout << arr[i][j] << "\t";

}

cout << endl;

}

for (int i = 0; i < m ; i++){

delete[] arr[i];

}

delete[] arr;

return 0;

}

5. C++ version - standard template library (STL) - vector - one and two dimension array
#include <vector>

#include

<string>

#include

<iostream>

using

namespace std;

int

main()

{

/* Case #1 - 1D vector */

vector<int> vector_1D;

vector_1D.push_back(5);

vector_1D.push_back(6);

vector_1D.push_back(7);

/* vector_1D has | int int int | */

for(int i=0;i<(int)vector_1D.size();i++)

cout << vector_1D[i] << endl;

vector_1D.clear(); // Actually, we don't need to delete allocated space.

// Vector will delete it for us when vector_1D is out of the scope.

/* Case #2 - 2D vector*/

int m=3, n=2;

vector<vector<int>> vector_2D;

vector_2D.resize(m); // there are m vector<int> variables

for (int i = 0; i < (int)vector_2D.size() ; i++){

vector_2D[i].resize(n);

}

/*

vector_2D has | vector<int> vector<int> vector<int> |

                              ||                   ||                  ||

                              ||                   ||                  ||

                              \/                  \/                  \/

                   has |int int|       has |int int|        has |int int|

*/

for (int i = 0; i < (int)vector_2D.size(); i++){

for (int j = 0; j <(int)vector_2D[i].size() ; j++){

vector_2D[i][j] = rand()%10;

cout << vector_2D[i][j] << "\t";

}

cout << endl;

}

return 0;

}

[C++] const的意義(const pointer, pointer to const, const pointer to a const, const function...)

#include<iostream>

#include<string>

using namespace std;

class A

{

private:

    int y;

public:

A(){

y=0;

}

int f1(int x) const // 此const代表此function不可以修改Data Member

{

x++;

// y++; // Error! y為Data Member,因此不可以修改

return y;

}

const int f2(int x) // 回傳值為const

{

x++;

y++;

return y;

}

int f3(int const x) // 參數為const

{

// x++; // Error! x為const,不可以修改

y++;

return y;

}

void f4(int const *x) // x is variable pointer to a constant integer,也可以寫成f4(const int *x)

{

// (*x)++; // Error! pointer x所指向的實體為const,因此不可以修改其值

*x++; // 此行的意思是*(x++),先修改pointer x的值,在指向實體

}

void f5(int const &x) // x is variable reference to a constant integer

{

// x++; // Error! x就是一個const

}

void f6(int *const x) // x constant pointer to a variable integer

{

(*x)++;

// *x++; // Error! Constant pointer x 不可以指向其他實體

}

const char * f7() // 回傳一個variable pointer to a constant char

{

return "ABC";

}

void f8(const int * const x) // x is constant pointer to a const integer

{

// (*x)++; // Error! x所指向的實體為const,因此不可以修改其值

// *x++; // Error! Constant pointer x 不可以指向其他實體

}

};

int main(){

A a;

int x=3;

a.f1(x);

a.f2(x);

a.f3(x); // int x 會自動轉成const int x傳入

a.f4(&x) ;

a.f5(x) ;

const char *s = a.f7(); // 必須使用一個const來接const

// s[0]='0'; // Error! 無法對const 變數進行改變動作

return 0;

}

 

Reference: http://duramecho.com/ComputerInformation/WhyHowCppConst.html

[C++] Virtual Destructor

#include <iostream>

#include <string>

#include <vector>

using namespace std;

/*

             1    *
Human -----> Tool
                        /\ 
                        |
                     |-----| 
                     |      |
                Pen   Pencil

*/

class Tool // the abstract class

{

public:

// no explicit constructor. there is a default one - Tool();

virtual void use() = 0;

virtual ~Tool(){

cout << "calling ~Tool()" << endl;

}

};

class Pen: public Tool

{

private:

int *x; // some private data;

public:

Pen(){

x = new int[100];

}

void use(){

    cout << "using the Pen" << endl;

}

~Pen(){

cout << "calling ~Pen()" << endl;

delete [] x; // x is a pointer to dynamically allocated memory space in this object. Pencil is responsible to delete the space.

}

};

class Pencil: public Tool

{

private:

char *y; // some private data;

public:

Pencil(){

y = new char[100];

}

void use(){

cout << "using the Pencil" << endl;

}

~Pencil(){

cout << "calling ~Pencil()" << endl;

delete [] y; // y is a pointer to dynamically allocated memory space in this object. Pencil is responsible to delete the space.

}

};

class Human

{

private:

vector<Tool*> tools;

public:

void addTool(Tool* tool){ // keep the pointers to Tools only.

tools.push_back(tool);

}

void paint() // use each tool

{

for (int i = 0; i < (int)tools.size() ; i++){

tools[i]->use();

}

}

virtual ~Human()

{

cout << "Calling ~Human()" << endl;

for (int i = 0; i < (int)tools.size() ; i++){

delete tools[i]; // if the tools are not shared between other Human, this Human object should delete the tools.

}

}

};

int main()

{

Human *human = new Human();

human->addTool(new Pen());

human->addTool(new Pen());

human->addTool(new Pencil());

human->paint();

delete human;

return 0;

}

/* output:

using the Pen

using the Pen

using the Pencil

Calling ~Human()

calling ~Pen()

calling ~Tool()

calling ~Pen()

calling ~Tool()

calling ~Pencil()

calling ~Tool()

*/

2010/03/20

台灣富人與外國窮人

【網路文章】有一回我到澳洲訪友,在居所附近的公園,遇上一個在河邊垂釣的中年男性。他很客氣主動與我招呼,我先是腆靦了一下,在台灣,陌生人的招呼是很不尋常的。他又主動問我從何處來,我說是台灣,他豎起大姆指說,那是一個富有的地方,他的熱情消除我的戒心,於是我們愉快地聊了起來。

原來,他以前是私人公司的主管,因為經濟不景氣,最近失業靠救濟金過生活,然而,從他悠閒從容的神情,實在看不出失業對他的生活有何壓力。

他啃著漢堡喝著脾酒,他調侃說,一天兩個漢飽、四罐脾酒,不到台幣二百元就解決了,一個月台幣兩萬元的救濟金還可以存著呢!

「可是,沒錢花你快樂嗎?」我提出在我們國家失業的人必定的疑惑。「為什麼不快樂?我每天安排不同的娛樂,今天到河邊釣魚,明天到海邊抓蝦蟹,後天到山上採野果,這些都是免費的食物與享受,為什麼一定要花錢?難道你們國家不是這樣嗎?」
說著同時,魚竿猛然往下拉,一翻激烈的博鬥,一尾肥美的鱸魚就上鉤了,這尾起碼有五斤重,在台灣至少要台幣四、五百元,而這裡卻是在小公園的河邊就唾手可得,他一天的娛樂與美食不就解決了嗎?沒錯!要那麼多錢幹嘛?

「不!在我們的國家沒有錢就沒有快樂,因為所有的快樂都是要花錢的,而且失業沒有救濟金,河裡釣不到魚,海裡抓不到蝦蟹,山上沒有野果,連公園裡的小水池都很髒,有錢人最大的快樂就是shopping,窮人就只能關在家裡看電視了。」我看著那隻生猛的魚沮喪說著。

「那麼你們賺的錢都花到那裡去?」他驚訝地問我。

這真把我給問倒了,沒錯!我們辛苦賺的錢,繳稅後都到那裡去了?為什麼這位老外的生活喜樂在我們國家都沒有? 我告別他後,望著那裡蒼鬱的林木、紛飛的野鴨、河流清澄的社區小公園想著,如果我可以選擇,我寧願在這裡做領救濟金的無業遊民,也不願在台灣當有錢人。

王永慶能呼吸到像這裡甘鮮甜美的空氣嗎?能在淡水河釣到鱸魚嗎?能到北海岸抓海碗大的螃蟹嗎?失業時還能悠哉地啃著漢堡、垂釣加菜嗎?

這樣看來,台灣首富生活品質還比不上澳洲的無業遊民。如果連王永慶都不能,我們市井小民又如何能在這塊土地安居樂業,享受生命呢? 近年來,我們的確富裕了,眼看著高樓大廈一棟棟由平地竄起,無數公路如一道道刀疤般切割過美麗的田園,五光十色的商業繁榮迷眩我們的眼睛,大街小巷被豪華車塞滿……

感覺上生活是富裕了,然而我們居家環境卻越來越亂,海岸線越來越醜,空氣品質越來越惡劣,我們的富裕似乎沒有給島民相同的生活品質與生命的快樂。

國民生活的富有,不在於有多高的國民所得,而是他們可以享受多少國家的公共建設、優良的居住環境與健全的福利制度。其實,市井小民最大的生活樂趣,不是在賺錢,而是在一個優美、乾淨、自然、原始的生活環境中享受生命,而不在醜陋的水泥叢林享受金錢堆砌出來的粗糙娛樂。

生活環境好,即使是窮人都覺得生命富裕,生活環境差,連富人都覺得一貧如洗。不同的是,富有的人厭惡台灣環境差,可以把破壞這個島嶼賺到的大筆鈔票用來移民,可以三天兩頭往國外揮霍享受,而市井小民就只能留在這個被搾乾的垃圾之島像溝鼠野狗般生活,這樣公平嗎?能忍受嗎?

停下為刺激經濟成長的各種破壞國土、犧牲環保的開發計劃,把這些錢花在河川整治,森林復育,美化海岸的環保工作,把過去因為為賺錢所造成的環境破壞慢慢修補回來。畢竟,美麗家園的喜悅,不是人民口袋有多少錢可以買到的。

好彌補對這母親之島五十年來的壓搾蹂躪吧,讓這片土地生活的子民,不論是窮人或有錢人都能平等享受這美麗國土的一切,讓我們恢復「福爾摩沙」子民的驕傲與光榮。我希望,那天在國外談起我的祖國,台灣時,他們誇讚的不是「有錢的島」而是「美麗的島」。

2010/03/17

[C++] Call by value、Call by pointer、Call by reference

在C語言裡裡,傳遞參數的2種方式,分別是Call by value、Call by pointer。而在C++裡多了一個Call by reference的方法。

Call by value

參數以數值方式傳遞,複製一個副本給另一個副程式。EX:

int main() {
    int x = 5;
    foo(x);
}

void foo(int x) {
    x++;
}

csie-tw.blogspot.com (1)

這時候main裡的變數x的值被複製到foo裡的x,這兩個x基本上是位於不同的記憶體空間的,也是就foo裡的x在加一後,並不會影響到main裡的x(依然是5)。

 

Call by pointer

Call by pointer是將變數的address傳到副程式,而副程式使用一個pointer接住這個address,因此副程式的這個pointer可以指向並修改這個數值。EX:

int main() {
    int x = 5;
    foo(&x);
}

void foo(int *x) {
    (*x)++; // 指向,並加1
}

csie-tw.blogspot.com (2)

main呼叫foo時,將x的address(&x)傳遞給foo的x pointer,所以x pointer指向回main的x,應此可以修改其數值。(*x)為指向其實體數值,因此(*x)++就是把main的x加1。

 

Call by reference

Call by reference的作用和目的和Call by pointer是一樣的,都是想要指回原本的變數並且可以修改。不過Call by reference寫起來更簡單。Ex:

int main() {
    int x = 5;
    foo(x); // 不用加&
}

void foo(int &x) {
    x++; // 修改此x就是修改main的x
}

csie-tw.blogspot.com

如果寫成call by pointer的方式,麻煩的地方是每次傳address都要加個 & ,而在副程式裡還要加個 * 來指向原本的實體。因此,C++新增了Call by reference的方式,讓在丟變數到副程式時,不用加&,而在副程式參做此變數也不用加*號就可以直接修改其變數。唯一要寫的是:在副程式裡的參數裡加上&,代表是Call by reference。

特別要注意的是,Call by reference的方式,一定要在初始化時就有指向的實體,而且不能改變。如上例中,foo(int &x)裡的x在副程式被呼叫時,就固定指向main的x,不能改變。

例題:

int a = 10, b = 20;

int &x = a; // pointer x一開始就要固定指向實體,這時候是指向a,無法改變。

x++; // a變成11

int *y; // y是一個pointer,可以在一開始不指向任何實體。

y = &b; // y指向b

(*y)++; // b變成21

y = &a; // y改為指向a

(*y)++; // a變成12

2010/03/08

Synergy:在多台電腦之間共享滑鼠鍵盤

有時候在工作場合上需要多台電腦工作。我常常遇到的問題是在不同的滑鼠鍵旁間游走,感覺滿不方便的。我後來就發現Synergy這套軟體,可以讓你用同一個鍵旁滑鼠就可以在多台電腦上工作。如下圖所示:我平常會在右邊的電腦工作,但是有時候會用左邊的電腦看文件。以下文章假設使用右邊電腦的滑鼠鍵盤控制2台電腦。

layout

1. 下載並安裝synergy:http://sourceforge.net/projects/synergy2/files/ 

2. 右邊電腦設定如下

2.1 點選AutoStart,讓電腦可以自動開機執行此程式。

2010-03-08_141951 

2.2 點選install即可開機執行。

2010-03-08_142015

2.3 接著點選「Configure」

2010-03-08_141951 

2.4 新增2台電腦的Screen name:點選「+」

2010-03-08_142430

2.5 為2台電腦命名。比如「cs-right」代表左邊電腦,「cs-right」代表右邊電腦。

2010-03-08_142439

2.6 定義2台電腦之間的位子。在下方細紅框的地方選擇他們的關係,比如:

the cs-right of left goes to cs-left

the cs-left of right goes to cs-right

2010-03-08_142652

2.7 設定右邊電腦(server)的screen name。點選:「Advance」。

2010-03-08_141951 

2.8 在screen name輸入:「cs-right」。

2010-03-08_142711

3. 左邊電腦設定如下

3.1 左邊電腦的角色為Client。在紅框1裡的Other computer's Host Name輸入:「cs-right」。

client1

3.2 設定左邊電腦的Screen Name,點選:「Advance」。

client1

2.8 在screen name輸入:「cs-left」。

clinet2

2.9 最後按下「Start」即可。

client1

Hello Qt Creator(安裝與簡易視窗程式)

Qt Creator是一套Qt的整合開發環境。可以在這邊下載http://qt.nokia.com/downloads
1. 安裝
點選Next
2010-03-07_230328
再點選Next,直到安裝完畢。
2010-03-07_230441
2. 建立新專案
2.1 開始Qt Creator
2010-03-07_234824
2.2 File->New File or Project
2010-03-07_234854
2.3 選擇Qt4 Gui Application  2010-03-07_235004
2.4 輸入專案名稱和路徑。注意:路徑名稱只能為純英文。
2010-03-08_013216 
2.4 選擇會用到的模組
2010-03-07_235050
2.5 設定主視窗名稱,使用預設即可。
2010-03-07_235104
2.6 Finish
2010-03-07_235112
2.7 點選Forms下的mainwindow.ui檔案,即可出現視窗介面。可以拖曳widget到window上。
2010-03-07_235736
2.8 點選左下方的綠色箭頭按鈕,即可執行程式。
2010-03-07_235957

2010/03/06

氣候紀錄片「正負2度C」:台灣恐成首批氣候難民

自由時報電子報 記者林嘉琪/台北報導〕氣候紀錄片「±2°C」昨天首映,科學家預警台灣恐成首批氣候難民,如果二一○○年前地球增溫超過二度,台灣嘉義東石港、屏東林邊、東港及全台最大的石化工業區雲林麥寮等地,將會沉沒或遭海水入侵;中研院地科所研究員汪中和表示,台灣不是氣候災難的化外之民,台灣的災難已經開始。

「目前全球平均溫度在十四.七度,已比一七五○年前高上○.八度。」汪中和指出,台灣早已成為氣候災民,莫拉克風災就是血淋淋的例子。如果全球溫度持續上升,海平面也會再升高,北冰洋一旦全融,會讓全球海洋升高六.六公尺,許多陸地將被淹沒。

紀錄片中科學家預測,約莫二○二○年到二○三七年的某年夏天,也就是最快十年以後,北極融冰會完全消失。結果會導致北冰洋海水溫度快速上升十度,因為它原本像是一面光鏡,把太陽光反射出去,現在卻變成一個大黑體,把太陽輻射吸進地球,一出一入之間,增加了二百倍熱量。科學家也發現,世界第一大島格陵蘭的冰河移動速度比四年前倍增,嚴重程度超乎想像。

聯合國在二○○九年列出,受到海平面上升影響的最危險各個國家三角洲,台灣危險地區包括蘭陽平原、台北盆地與高雄市。

建議參考荷蘭 研發水上房屋

±2°C」建議台灣參考荷蘭的因應措施。荷蘭新的國土規劃,預算規模超過國防預算,「還土於海」、「還土於河」,並致力研發水上房屋,準備好面對二○三五年海平面上升後的新地球生態。

±2°C」片中呈現中央氣象局資料,把台灣從一九四七到一九九六年間的每一條襲台颱風路徑畫成一條直線,台灣像是一塊被竹編包得密不透風的土地,雨量最密集地區就落在花蓮與阿里山以下的中南部地區。去年莫拉克襲台兩個月後,台灣最北端的翡翠灣,居然佈滿來自中部山區及阿里山區的樹木,山崩樹倒、山林遷徙,顯示「氣候的力量,超越戰爭」。

立法院長王金平昨晚看過「±2°C」氣候紀錄片表示,希望立院本會期務必要排除萬難,讓溫減法通過,立法委員田秋堇則指出,環團都認為現行溫減法版本是個爛法,除非政府明文訂出碳預算(數量),否則溫減法易流於圖利財團,台灣沒有碳主權,未來還可能遭遇碳制裁。

企業家批政府不懂環保議題

台達電子董事長鄭崇華批評,政府官員不懂環保議題,以美國牛進口為例,畜牧及運送肉品到台灣已產出太多二氧化碳。清楚點出台灣環保政策都在政策考量之後。華碩電腦董事長施崇棠個人吃素減碳;鴻海董事長郭台銘看完紀錄片快步離開現場,只說現在就要以行動救地球。

±2°C」不選擇於全台戲院放映,主要是考慮民眾到戲院觀看會帶來更多碳排放足跡,台灣的多家電視台,包括緯來、Discovery Channel、慈濟大愛、人間衛視及中華電信MOD等頻道,都已加入無償播放紀錄片行列。該片也能在官方網站(http://正負2度c.tw )讓民眾免費下載。

正負2度C紀錄片8-1

正負2度C紀錄片8-2

正負2度C紀錄片8-3

正負2度C紀錄片8-4

正負2度C紀錄片8-5

正負2度C紀錄片8-6

正負2度C紀錄片8-7

正負2度C紀錄片8-8

2024年React state management趨勢

輕量化 在過去Redux 是 React 狀態管理的首選函式庫。 Redux 提供了強大的功能和靈活性,但也帶來了一定的學習成本和複雜度。 隨著 React 生態的不斷發展,越來越多的開發者開始追求輕量化的狀態管理函式庫。 Zustand 和 Recoil 等庫以其簡單易用、性...