發信人: 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.]
.