面向物件程式設計(C++篇1)——引言
1. 概述
現代C++與最原始的版本已經差不多是兩種不同的語言了。不斷髮展的C++標準給C++這門語言帶來了更多的正規化和特性,也造就了其非常的難度。但是從個人的體會而言,如此之多的特性沒有必要一項項去硬學,很多的特性沒有實際使用過,體會就不會很深。反而在學了C#,Java,JavaScript這些語言並在實際使用過之後,反而愈發理解了這些語言的程式設計思想。
現代C++至少有4種程式設計正規化:面向過程、面向物件、泛型和函式式。其中面向物件是最經典的程式設計思想,最初的時候使用C++的面向物件,總是用成了"C With Class"風格。但是其實在Cpp11之後面向物件有一整套獨特的設計,體現了C++"零成本抽象(zero overhead abstraction)"的設計哲學。
2. 詳論
2.1. 類與物件
任何程式語言都有資料型別的概念,如整型、浮點型等。但是很快,有時候我們發現,全部是單個的資料型別不利於管理,所以有個自定義資料型別。例如,我想定義一個影象型別:
struct ImageEx
{
int imgWidth;
int imgHeight;
int bandCount;
};
struct最開始是C語言的定義,也就是結構體。通過這個簡單的影象型別結構體,管理了影象寬、高以及波段三個引數。通過struct雖然讓程式設計中有了一定對現實事物的抽象能力,但是這個能力是不足的。主要是缺少像函式一樣的“行為”能力。而在C++中,對struct做了擴充,我們在其中加入函式來表達行為(這裡通過函式DoWork()表達對影象的某種處理):
struct ImageEx
{
int imgWidth;
int imgHeight;
int bandCount;
void DoWork()
{
}
};
像這樣,把資料(屬性)和函式(方法)合成的自定義資料結構,就是類,其具體的例項就是物件,以物件最為程式設計的基本單位就是面向物件程式設計。它表達了對客觀事物的抽象,更接近於人的自然認知。
更多的情況下,C++的類採用class關鍵字。class和struct的區別在於,class定義類的資料成員和成員函式預設的訪問許可權是public:公有的,能被外部訪問;而struct則是private:私有的,不能被外部訪問。當然,我們最好明確訪問許可權:
class ImageEx
{
public:
void DoWork()
{
}
private:
int imgWidth;
int imgHeight;
int bandCount;
};
增加訪問許可權控制的好處是進一步加強了類的封裝性。對於任何一個類物件,使用者肯定更關心其行為方法,而不是其內部屬性部據。因此,通常一個比較好的實現是:方法在前,設為public,資料在後,設為private。
進一步的,如果在公有的成員函式很複雜,需要通過呼叫其他成員函式DoSomething()來實現,那麼這個DoSomething()函式定義成公有還是私有的呢?通常來講,可以定義成私有:
class ImageEx
{
public:
void DoWork()
{
DoSomething();
}
private:
void DoSomething()
{
}
int imgWidth;
int imgHeight;
int bandCount;
};
這樣,通過資料抽象和封裝,實現了介面與實現的分離。可以認為類的介面是類的公有成員函式,而類的資料成員、介面實現的函式體、類的私有成員函式是類的實現。類的設計者負責類的具體實現過程,類的使用者則只需要抽象的思考類做了什麼,無需瞭解型別的工作細節。
2.2. 資料型別
在以前經典的程式設計學習中,會逐漸從資料型別、表示式、語句、函式,最後才會學到類,接觸面向物件的思想。而在現代以面向物件為基礎的程式語言(C#、Java、JavaScript)來說:
- 類是抽象的自定義資料型別,只不過這個資料型別有自己的屬性和方法,以及一系列表達抽象物件的特性。
- 語言內建的資料型別也可以認為是一種類,事物物件抽象到極致,就是基本的資料型別。
在C#/Java這樣的高階程式語言中,你可以在基本型別中呼叫其方法;而JavaScript甚至更進一步,弱化了型別這個概念,所有的型別都是隱式的。C++具備像這樣的高階抽象能力,但是也相容C語言那種低階的基礎資料型別(short、int、long、char、float、double)。這也正體現了C++的多正規化程式設計的特點:如何看待資料型別和類,取決於你採用面向物件的程式設計思想還是面向過程式的程式設計思想。