精華區beta b885060xx 關於我們 聯絡資訊
發信人: YHH.bbs@bbs.iljhs.il.edu.tw (工藤新一), 看板: programming 標 題: OOP by C++ (2) [轉載] (轉載) 發信站: 宜蘭資教 山水蘭陽 (Tue Aug 19 23:23:21 1997) 轉信站: sobee!netnews.ntu!iljhs 本文轉載自 PCtrick 討論區,原作者為 YHH C++物件導向程式語言簡明教程之二 <第二章 概論 II > 撰文:程式創作區 小樹 使用編譯器:Turbo C++ 3.0 讀者須知: 本文章由C 開始談起,算是一篇C++的入門參考書 文內假設各位已經有C語言的基礎,是C++的初學者, 讀者至少必須對C有相當程度的熟悉, 如流程控制(if,for,while,switch...),指標,陣列,結構(struct), 都必須非常熟悉, 否則恐怕會有閱讀上的困難. 本文件的目的是想要讓C++更好學, 使大家都能輕易的瞭解C++的精義. 因此本文件歡迎傳閱, 若有需要也歡迎做適當的修改, 以修正錯誤或增加可讀性. 但請勿加入不雅的言語, 而且修改者務必註明修改者名稱及修改日期, 並保留原作者之簽名. 謝謝各位! <1> 再談類別繼承 讓我們來繼續談上一回的繼承. 在繼承關係中, 一個類別的上一層稱為此類別之父類別, 一個類別的下一層稱為此類別之子類別或衍生類別. 例如生物類別為動物類別之父類別, 動物類別為生物類別之子類別. C++有一個規定:"一個父類別的指標可以指向一個他的子類別" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 請看: class father { }; class son:public father { }; void main() { father *man; son peter; man=&peter; } 以上的敘述完全合法, 不會有任何錯誤. 至於有什麼用途, 等我們真正開始做程式時你就會明瞭! <2> 虛擬函式 我們改造一下上一個例子: class father { public: DoJob();//做工作 }; class son:public father { public: DoJob();//做工作 }; void main() { father *man;//父親類別指標 son peter; man=&peter; //父親的指標可以指向兒子,這是上一章才說過的 man->DoJob();//到底是爸爸的DoJob會被呼叫呢?還是兒子的? } 在上例中,爸爸和兒子都多了一個成員函式--DoJob() 意思是叫他們作自己的工作的意思!! 由於爸爸的工作和兒子不同,所以內容當然不一樣啦!! 以上面的寫法, 雖然man是指到peter man->Dojob()應該要執行的是兒子的工作, 但是程式到底會叫兒子執行爸爸的工作呢? 而是作自己的工作呢? 其實程式的本意當然是希望兒子執行他自己的工作啦!!(因為man指到的是peter啊!!) 可是照上面的寫法,C++卻會執行爸爸的工作.... 要讓程式能執行指標所指到的人的函式, 程式必須這麼寫: class father { public: virtual DoJob();//做工作 }; class son:public father { public: virtual DoJob();//做工作 }; void main() { father *man; son peter; man=&peter; man->DoJob();//因為指標指到的是兒子,所以兒子做工作 } 上面的程式在函式前多加了"virtual"敘述, 稱作虛擬函式, 加上去之後,程式便會根據指標所指的人,去執行他該做的事 這樣瞭解嗎? 虛擬函式又叫動態連結,或晚連結 因為到底要執行誰的函式要等到實際執行才知道. <3> 參考型別 在C++中,提供了一個C 所沒有的特性--"參考型別" 其實參考型別沒有什麼,他只是替物件建立一個別名罷了! 請看: int i=5; //i 是個int 物件 int &j=i;//j 是 i 的別名,即j 是i 的參考,明白的說,i 和 j 是同一個變數的不同名字 i++; //執行後 i 變成6 j++; //因為j 就是i ,故i 此時為7 所謂的"參考",其實就是別名. 就好像蔣中正又叫蔣介石一樣. 其實j 和i 是同一個變數, 只是名字不同罷了!! 這樣懂乎? 其實如果只有這樣, 那參考還真是沒什麼用處! 事實上參考最大的用處,在於函式傳參數時使用. 請看下例: struct test //一個結構 { int string[1000]; }; void function(test value) //此函式會印出value.string { cout << value.string; } void main() { test a; //建立一個a物件 function(a); //將a傳給函式 } test結構是一個很大的結構, 光是a 這個物件就至少要佔掉2000 bytes的記憶體, 各位想想, 當我將a 傳給function 的時候, 因為是傳值, 所以C++會先做出一個test結構的 value物件, 然後再將a 一個位元一個位元的copy 給value, 天啊! 這既佔記憶體又耗時間, 如果我能直接將a 拿給function函式使用的話多好啊!! 用傳參考就可以做到這一點, 而且不會像傳址那麼彆扭, 請看改進後的程式碼: struct test //一個結構 { int string[1000]; }; void function(test & value) //傳參考,這裡多了一個 & 符號 { cout << value.string; } void main() { test a; //建立一個a物件 function(a); //將a傳給函式,注意!!函式用法不變喔!! } 只要照上面這樣寫, value 就會是a 的別名, 也就是說value 就是 a啦!!!(但是生存期跟傳值時一樣) 不必多佔記憶體, 也不必花copy物件的時間. 這不是很好嗎!!! 參考的用處就在此, 這樣瞭解嗎? <4> const 物件 相信熟悉C 語言的你, 對"#define"這個關鍵字應該很熟了吧!! 使用#define 可以在C語言中定義出常數, 例: #define PI 3.1416159 //定義常數PI void main() { cout << PI; //印出PI } 可是#define使用在C++中卻有缺陷, (不過這個缺陷不是重點,為省各位的腦力我就不講啦!!) 為此C++提出了新的定義常數的方法---const 物件!! 請看: const double PI=3.1416159; void main() { cout << PI;//印出PI PI=10;//錯誤!!!const 物件不能被更改 } 所謂的const 物件, 其實他和一般的物件一樣, 但是他在定義後就不能改值了, 而且在定義時就必須要給初值,(不給不行喔!!) 若嘗試著去更動const物件, 則編譯器會給予警告, 並終止編譯!! <5> 行內函式 相信各位C 的高手們對巨集函式應該不陌生吧!! 巨集函式有執行速度快的優點, 可是C 的巨集函數卻是很麻煩, 一個不小心就會留下難以除錯的BUG!! C++提供了行內函式, 用以取代傳統C 之巨集!! 其實行內函式很簡單, 只要在函式名字的前面加上"inline"的識別字, C++就會視情況將行內函式拓展成巨集, 請看: inline int max(int a,int b) { if(a>b) return a; else return b; } 如此一來,max就是一個快速的巨集函式了!! 值得注意的是: 行內函式為巨集,故不可遞迴, 即不可呼叫自己. 現在讓我們來回溯一下我們第一章所建立的子彈類別: class _Bullet//這是一個 "子彈" 的 "模子",改用class來寫 { private://私用成員 int x; int y; void show(int x,int y);//這是一個函式,可以在(x,y)上畫出一點, public://公用成員 _Bullet(){x=y=0;}//無參數之建構函式 _Bullet(int X,int Y){x=X;y=Y;}//有兩個參數之建構函式 void go()//這是一個函式,呼叫他可以讓子彈往下移一格並畫出來 { show(x,y); y++; } int collision(int X,int Y)//這是一個函式,用來判斷子彈是否撞到東西 { return (x==X && Y==y); //不是則傳回0 } }; 在這個類別中,類別內函式成員都是定義在類別中,(注意!!定義和宣告是不一樣的!!) 其實我們也可以定義在類別外的, 請看: class _Bullet { private: int x; int y; void show(int x,int y); public: _Bullet(); //只宣告不定義 _Bullet(int X,int Y); void go(); int collision(int X,int Y); }; _Bullet::_Bullet() //定義在外的建構函式 { x=y=0; } _Bullet::_Bullet(int X,int Y) //同上 { x=X; y=Y; } void _Bullet::go() //同上 { show(x,y); y++; } int _Bullet::collision(int X,int Y) //同上 { return (x==X && Y==y); } 一個類別的函式成員若過大, 定義在外面是比較好的, 因為這樣子好看多了!! 相信從上例大家應該可以學會類別內函式定義在外的語法!! 若要將類別的函式成員定義在外, 其語法為: 函式傳回值 所屬類別::函式名(參數) { ...... } 基本上,對於定義在內的成員,C++會將其編碼為行內函式, 定義在外的則編碼為一般函式!! 若要定義在外的也為行內函式, 只要加上inline敘述即可!! <第二章結束> <待續> 小樹 1996 8/16 ※ 來源:‧山水蘭陽資訊站 bbs.iljhs.il.edu.tw‧[FROM: dia38.iljhs.il.] .