基礎知識
繼承機制定義了父子(parent/child)關系,父類(parent)定義了所有子類(children)共通的共有介面(public interface)和私有實作(private implementation),每個子類都可以增加或覆寫(override)繼承而來的東西,以實作其自身獨特的行為,在C++中,父類被稱為基類(base class),子類被稱為(derive class),父類和子類之間的關系則稱為繼承體系(inheritance hierarchy),
多型:讓基類的pointer或reference得以十分透明地(transparently)指向其任何一個派生類的物件,在程式執行之前就已決議出應該呼叫哪一個函式,這種方式被稱為靜態系結(static binding);但在面向物件編程方法中,編譯器無法得知具體哪一份函式會被呼叫,這一決議操作會延遲至運行時(run-time)才進行,這就是所謂的動態系結(dynamic binding),
定義抽象類第一個步驟就是找出所有子類共通的操作行為,然后便是設法找出哪些操作行為與型別相關(type-dependent),也就是說有哪些操作行為必須根據不同的派生類而有不同的實作方式,這些操作行為應該成為整個繼承體系中的虛函式(virtual function),
設計抽象基類時,我們需要找出每一個操作行為的訪問層級(access level),如果某個操作行為應該讓一般程式皆能訪問,我們應該將它宣告為public;但如果某個操作行為在基類之外不需要被用到,我們就將它宣告為private,即使是該基類的派生類,亦無法訪問基類中的private member;一個訪問層級就是protected,這種層級行為可讓派生類訪問,不允許一般程式使用,
每個虛函式,要么得有其定義,要么可設為“純”虛函式(pure virtual function),如果對于該類而言,這個虛函式并無實質意義的話,將虛函式賦值為0,意思便是另它為一個純虛函式,任何類如果宣告有一個(或多個)純虛函式,那么,由于其介面的不完整性(純虛函式沒有函式定義,是謂不完整),程式無法為它產生任何物件,這種類只能作為派生類的子物件(subobject)使用,而且前提是這些派生類必須為所有虛函式提供確切的定義,另外根據一般規則,凡基類定義有一個(或多個)虛函式,應該要將其destructor宣告為virtual,
派生類由兩部分組成:一是基類構成的子物件,由基類的non-static data member——如果有的話——組成;二是派生類的部分(由派生類的non
-static data member組成),類進行繼承宣告之前,其基類的定義必須已經存在,
data member如果是個reference,必須在constructor的member initialization list中加以初始化,一旦初始化,就再也無法指向另一個物件,如果data member是個pointer,就無此限制:我們可以在constructor內加以初始化,也可以先將它初始化為null,稍后再另它指向某個有效的記憶體地址,程式設計程序中我們便是根據這些不同的性質來決定要使用reference或pointer,
當我們定義派生類時,我們必須決定,究竟要將基類中的虛函式覆寫掉,還是原封不動地加以繼承,如果我們繼承了純虛函式(pure virtual function),那么這個派生類也會被視為抽象類,也就無法為它定義任何物件,如果我們決定覆寫基類所提供的虛函式,那么派生類提供的新定義,其函式運行必須完全符合基類所宣告的函式原型,包括:引數串列、回傳型別、常量性(const-ness),而且進行宣告操作時,不一定得加上關鍵字virtual,編譯器會依據兩個函式的原型宣告,決定某個函式是否會覆寫其基類中的同名函式,
練習題答案
練習5.1 實作一個兩層的stack(堆疊)類體系,其基類是個純抽象類Stack,只提供最簡單的介面:pop()、push()、size()、empty()、full()、peek()和print(),兩個派生類則為LIFO_Stack和Peekback_Stack,Peekback_Stack()可以讓用戶在不更改stack元素的前提下,訪問任何一個元素,
#include <iostream> #include <string> #include <vector> using namespace std; typedef string elemType; class Stack { public: virtual ~Stack(){} virtual bool pop(elemType&) = 0; virtual bool push(const elemType&) = 0; virtual bool peek(int index, elemType&) = 0; virtual int top() const = 0; virtual int size() const = 0; virtual bool empty() const = 0; virtual bool full() const = 0; virtual void print(ostream& = cout) const = 0; }; ostream& operator<<(ostream& os, const Stack& rhs) { rhs.print(); return os; } class LIFO_Stack :public Stack { public: LIFO_Stack(int capacity = 0) :_top(0) { if (capacity) _stack.reserve(capacity); } int size() const { return _stack.size(); } bool empty()const { return !_top; } bool full() const { return size() >= _stack.max_size(); } int top() const { return _top; } void print(ostream& os = cout) const; bool pop(elemType& elem); bool push(const elemType& elem); bool peek(int, elemType&) { return false; } private: vector<elemType> _stack; int _top; }; bool LIFO_Stack::pop(elemType& elem) { if (empty()) return false; elem = _stack[--_top]; _stack.pop_back(); return true; } bool LIFO_Stack::push(const elemType& elem) { if (full()) return false; _stack.push_back(elem); ++_top; return true; } void LIFO_Stack::print(ostream& os) const { vector<elemType>::const_reverse_iterator rit = _stack.rbegin(), rend = _stack.rend(); os << "\n\t"; while (rit != rend) { os << *rit++ << "\n\t"; } os << endl; } class Peekback_Stack :public Stack { public: Peekback_Stack(int capacity = 0) :_top(0) { if (capacity) _stack.reserve(capacity); } int size() const { return _stack.size(); } bool empty()const { return !_top; } bool full() const { return size() >= _stack.max_size(); } int top() const { return _top; } void print(ostream& os = cout) const; bool pop(elemType& elem); bool push(const elemType& elem); bool peek(int, elemType&); private: vector<elemType> _stack; int _top; }; bool Peekback_Stack::pop(elemType& elem) { if (empty()) return false; elem = _stack[--_top]; _stack.pop_back(); return true; } bool Peekback_Stack::push(const elemType& elem) { if (full()) return false; _stack.push_back(elem); ++_top; return true; } void Peekback_Stack::print(ostream& os) const { vector<elemType>::const_reverse_iterator rit = _stack.rbegin(), rend = _stack.rend(); os << "\n\t"; while (rit != rend) { os << *rit++ << "\n\t"; } os << endl; } bool Peekback_Stack::peek(int index, elemType& elem) { if (empty()) return false; if (index < 0 || index >= size()) return false; elem = _stack[index]; return true; } //non-member function peek()接受一個“抽象類Stack的reference”作為引數, //并在函式內呼叫該Stack物件的虛函式peek()——此虛函式乃各派生類所特有, void peek(Stack& st, int index) { cout << endl; string t; if (st.peek(index, t)) cout << "peek: " << t; else cout << "peek failed!"; cout << endl; } int main() { LIFO_Stack st; string str; while (cin >> str && !st.full()) st.push(str); cout << '\n' << "About to call peek() with LIFO_Stack" << endl; peek(st, st.top() - 1); cout << st; Peekback_Stack pst; while (!st.empty()) { string t; if (st.pop(t)) pst.push(t); } cout << "About to call peek() with Peekback_Stack" << endl; peek(pst, pst.top() - 1); cout << pst; return 0; }
end,
“博學慎思,明辨篤行,”
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/63263.html
標籤:C++
