封裝(encapsulation) :將物件內部的資料隱藏起來(private or protected),只能透過物件本身所提供的介面取得五件內部屬性或是方法,物件內部的細節資料或是邏輯隱藏起來,要存取物件內部的資料,只能透過設定好的方法處理。 在上述的例子中,就是利用 getinformation() 取得車子資訊,但是不用知道如何取得的。
繼承(inheritance):一個類別的子類別,可以繼承父類別的屬性跟方法,也新增自己的屬性。如上述的車跟計程車
多型(polymorphism):1. 多載(overloading): 相同類別中,定一名稱相同,但是參數個數不同,可以利用參數個數或是型態互叫不同的方法,如同上述的Taxi 內,有三個變數跟四個變數的,就有不一樣的處理方法。2. 複寫(overriding) :覆蓋掉父類別的函式,ex 把 getinformation 變成 taxi版本。
補充:
protect: 這個部分是為了讓子類別能夠存取某些base的資料,但是又不想要讓別人使用到的時候就會將這個變數放在protect 。
首先要先定義類別(class)跟物件(object),類別(class)是某類事物的抽象特點,類別會包含了資料的形式以及對資料的操作方法。
物件(object),又叫做類別的實例(instance),也就是利用class製作許多不同的資料。
舉例來說,類別叫做汽車,這樣可以利用汽車這個類別區分出各種不同的車款,BMW 拉! Honda拉!….
在上面的程式碼中, 如果三個argument的名稱跟三個要assign的變數名稱相同,則會沒辦法把東西正確傳遞,要使用 this→brand = brand,才能夠把資料傳進去。
static binding vs dynamic binding
binding 是把一個東西對應到另一個東西上,在C++裡面bindin指的是函示呼叫跟函式定義的連接,會發生在 compile-time or run-time.
在compile-time 發生的binding 稱之為static binding,又稱為early-binding
在run-time 發生的binding 稱之為dynamic binding 又稱為late-binding.
靜態繫結的優勢是所有函式鏈結的資訊都已經提前知道了,所以程式執行起來會比較快。
動態繫結的好處在run-time才決定,所以可以更彈性的呼叫函式。
函式宣告(function declare) 會告訴compiler 該函式的名字回傳型別跟傳入的參數,但是省略了實際的主體。
函式定義(function define) 提供compiler 該函式的主體跟內容等等細節。
如以下的式子
當我們提到inheritance時,要先想清楚該function想繼承的是 declare 還是 definition ,承襲了前面的部分, inheritance of interface 繼承宣告, inheritance of implementation 繼承函式的定義。
有三種狀況,只想繼承函式宣告。想繼承函式宣告跟定義,但允許override定義,想要繼承兩者,但不允許override定義。
以上面的 Shape 來説,因為它包含了一個以上的 pure virtual 函式,所以他是個abstract class,所以他沒有辦法創造 Shape物件,只有在shape 的subclass (子物件)才可以。
宣告pure virtual 函式的意義是,derived class 僅僅繼承函式的interface,definition要自己處理
Shape::draw 在通告所有的 derived class ,你必須要提供 draw 函式,要怎麼實作我不管。
像是要畫出矩形跟圓形的方法應該是不一樣的。
simple virtual function : 也就是有virtual 但是後面沒有0的
宣告 simple virtual 函式的意義為,derived class 繼承函式的 interface 以及其 default implementation
在simple virtual函式,derived class 繼承了函式的interface ,simple virtual 函式會提供基礎的implemetation,但derived class 可以override 。 Q: 一般的函式就不能override嗎
Shape 透過這個意思告訴所有 derived class「你要提供 error 函式,但如果你不想要寫自己的版本的話,你可以用我的版本」。
宣告 non-virtual 函式的意義為,繼承函式的 interface 以及不更改函式原本的 implementation。
純虛擬函式 (pure virtual function) 與抽象類別(abstract class) :
類別中可以定義純虛擬函式,純虛擬函式就是沒有函式內容的函式,方法為:
virtual typeT funcname() = 0;
簡單來說可以說是,前有virtual 後有 =0 即是
在一個class中只要有至少一個純虛擬函式,該類別就被稱為抽象類別,一個類別不能產生物件,只能用來被繼承,如果被用來產生物件,則會報錯
virtual 的好處是避免掉了程式碼的 replication,但缺點是 class 裡面會需要多佔一些空間以及 run-time 會比較慢一些,當然還有一些 virtual 的其他小細節,像是 polymorphic bases class 中 destructor 盡量要 virtual、盡量避免讓 virtual 遇上 inline、在 multiple inheritance 中 virtual base class 的意義、如果要 override virtual 函式的話最好加上 override 等等,有興趣的話可以繼續探索下去。
effective c++ item 34
Q virtual function and override
在閱讀這篇文章的時候,對於文章的內容有點不理解,是在關於simple function 的override的部分,發現就override來説,好像simple function 跟 virtual function 沒有什麼差別的感覺。提出了以下的例子
根據以下的例子鄭教授為了讓我理解他的精妙,對我自己的例子進行修改,主要修改的點只有一個 把pointer都變成是base class的pointer 這樣的做法會發生什麼事情呢?請看output
發現了嗎,問題是在A pointer,ptr1, ptr2 都變成程式A class 的pointer,因為他是同一個類別的衍生類,所以可以這樣使用。
雖然在建立實體的時候,一個類別是 A一個類別是B 但是他們都可以使用原始的base class的pointer進行指向。只是其中不一樣的事情是,virtual function 會依照指標的類別,去找相應的virtual table 進行function查找,所以如果是用A pointer他就只會去找 A class的virtual table。如果是非virtual 的simple function呢?因為他的記憶體已經寫死了,所以即便pointer 是class A 但是裡面的function的記憶體位子仍然是class B的function address 。
所以同樣是a pointer to A class ,當他指向 base class的時候,會是執行 base class的實作,如果改成指向 derived class ,那麼他就會去查找子類的表,找到子類的實作。
example :
交通工具都能夠前進,那我只要知道交通工具能夠前進就可以了,我不用知道他是哪一種交通工具,只要是交通工具的衍生類都會有前進的選項,在實行時期再看他是哪一種交通工具決定他是怎麼前進的。
所以叫做動態多型的理由就是因為他要執行什麼function 是在執行時期確定是哪個衍生類之後,再去virtual table 找到目標的。
不過上面的virtual table 被override這件事,並不代表在derived class 就沒辦法呼叫那些被取代的function ,只是要利用特殊的方法。 ptr2->A::b(); 不管ptr2 是 A* B*都可以成立。
只要是子類別,我都可以利用父類別的指標去指向我原本就有的函數,所以才叫多態,看起來是同個型態的指標可是行為是動態決定的,為了支援使用該funciton 的時候不需要確切知道他是哪種東西就可執行
ex : 遊戲的職業有很多種,魔法師拉戰士拉… 他們都有一個叫做攻擊的func,用了這個方法我不需要在乎他本身是什麼類別,而是知道他就是一個人物,能夠攻擊,然後因為pointer 會指到該人物的virtual table 去找尋他的攻擊function 是什麼!
補如果是靜態多型……
最後補一個完整的例子,如果有一個base class 叫做動物,他會叫,可以寫成以下形式,
小到大,先做其他建構子,再處理