三个一流的设计继承
通過繼承可以派生新類從現有的類。派生類繼承了基類的功能,包含方法。
財產要比自己白手起家easy一樣。通過繼承派生出的類通常比設計新類要easy得多。
以下是可以通過繼承完畢的一些工作。
①能夠在已有類的基礎上加入功能。
②能夠給類加入數據。
③能夠改動類方法的行為。
C++有三種繼承方式:公有繼承、保護繼承和私有繼承。
一、公有繼承
公有繼承是最經常使用的方式。它建立一種is-a關系。即派生類對象也是一個基類對象。能夠對基類對象運行的不論什么操作,也能夠對派生類對象運行。
①公有繼承不建立has-a關系。比如,午餐可能包括水果??墒峭ǔN绮筒⒎撬?#xff0c;因此不能從水果類派生出午餐類。
②公有繼承不能建立is-like-a關系,也就是說,它不採用明喻。
人們通常說律師就是鯊魚,可是律師并非鯊魚,因此不能從鯊魚派生出律師。
③公有繼承不建立is-implemented-as-a(作為......來實現)關系。比如。能夠用數組來實現堆棧,可是從數組類派生出堆棧類時不合適的,由于堆棧不是數組,至少數組索引不是堆棧的屬性。正確做法是:通過讓堆棧包括一個私有數組對象成員。來隱藏數組實現。
④公有繼承不建立uses-a關系。
比如,計算機能夠使用激光打印機,可是從Computer類派生出Printer類是沒有意義的。只是能夠使用友元函數或類來處理Printer對象和Computer對象之間的關系。
多態公有繼承
實現機制:
①在派生類中又一次定義基類的方法。
②使用虛方法。
比如:
class A
{
public:
?virtual ~A(){}
?virtual void show()
?{
??cout << "A" << endl;
?}
};
class B:public A
{
public:
?void show()
?{
??cout << "B" << endl;
?}
};
class C:public B
{
public:
?void show()
?{
??cout << "C" << endl;
?}
};
int main()
{
??C c;
?A a;
??A *pA = new C;
?B b;
?B *pB = new C;
?a.show();
?b.show();
?c.show();
?pA->show();
?pB->show();
?delete pA。
?delete pB;
}
1)能夠看出基類中的方法show()在派生類中的行為是不同的,程序將使用對象類型來確定使用哪個版本號。比如:
a.show();//use A::show()
b.show();//use B::show()
c.show();//use C::show()
2)使用virtual之后。假設方法是通過引用或者指針而不是對象引用的,它將確定使用那一種方法。
假設沒有使用keywordvirtual。程序將依據引用類型或指針類型選擇方法。假設使用了virtual,程序將依據引用或指針指向的對象的類型來選擇方法。比如:
假設基類中的show()沒有使用virtual,那么
pA->show();//use A::show()
pB->show();//use B::show()
假設基類中的show()使用了virtual,那么
pA->show();//use C::show()
pB->show();//use C::show()
大家可能會疑惑,類B作為類C的基類。當中的方法show()沒有被聲明為virtual,可是為什么相同調用的是對象c中的方法。
這里我們必須清楚一點。方法在基類中被聲明為虛擬后,它在派生類中將自己主動成為虛方法。
3)基類聲明類一個虛擬析構函數,這樣做是為了確保釋放派生對象時,依照正確的順序調用析構函數。當使用delete釋放由new分配的對象時,假設析構函數不是虛擬的,則將僅僅調用相應于指針類型的析構函數,比如上面的僅僅調用類型A和類型B的析構函數,即使指針指向的是一個C對象。
假設析構函數是虛擬的。將調用相應對象類型的析構函數。因此假設指針指向的C對象,將調用C的析構函數,然后子宮調用基類的析構函數。因此。使用虛擬析構函數能夠確保正確的析構函數序列被調用。
4)private和protected之間的差別僅僅有在基類派生類中才會表現出來。
派生類的成員能夠直接訪問基類的保護成員。但不能直接訪問基類的私有成員。因此對于外部世界來說。保護成員的行為與私有成員類似;但對于派生類來說。保護成員的行為與公有成員相似。
5)構造函數不能是虛函數。創建派生類對象時,將調用派生類的構造函數,而不是基類的構造函數,然后。派生類的構造函數將使用基類的一個構造函數。這樣的順序不同于繼承機制。
因此。派生類不繼承基類的構造函數,所以將類構造函數聲明為虛擬的沒有什么意義。
二、私有繼承
C++的一個主要目標是促進代碼重用。公有繼承是實現這樣的目標的機制之中的一個。但并非惟一的機制。假設一個類本身是還有一個類的對象。這樣的方法稱為包括、組合或層次化。
還能夠通過使用私有或保護繼承,實現這樣的包括關系。
通常,包括、私有繼承和保護繼承用于實現has-a關系。即新的類將包括還有一個類的對象。
使用私有繼承,基類的公有成員和保護成員都將成為派生類的私有成員。這意味著基類方法將不會稱為派生類對象公有接口的一部分,但能夠在派生類的成員函數中使用它們。
使用公有繼承。基類的公有方法將成為派生類的公有方法。
簡而言之,派生類將繼承基類的接口;這是is-a關系的一部分。
使用私有繼承?;惖墓蟹椒▽⒊蔀榕缮惖乃接蟹椒?。簡而言之,派生類不繼承基類的接口。這樣的不全然繼承是has-a關系的一部分。
包括將對象作為一個命名的成員對象加入到類中,而私有繼承將對象作為一個未被命名的繼承對象加入到類中。
包括:
#include <string>
#include <valarray>
using namespace std;
class student
{
public:
?double Average() const;
private:
?typedef valarray<double> ArrayDb;
?string name;//contained object
?ArrayDb scores;//contained object
};
私有繼承:
class student:private string,private valarray<double>
{
public:
?double Average() const;
?const string& Name() const;
...
};
1)初始化基類組件
對于構造函數。包括將使用這種構造函數:
student(const char* str,const double* pd,int n)
?:name(str),scores(pd,n){}
對于繼承類,它使用類名而不是成員名來標識構造函數:
student(const char* str,const double* pd,int n)
?:string(str),valarray<double>(pd,n){}
2)訪問基類的方法
包括使用對象來調用方法:
double student::Average() const
{
?if (scores.size() > 0)
??return scores.sum()/scores.size();
?else
??return 0;
}
而私有繼承使得可以使用類名和作用域解析操作符來調用基類的方法:
double student::Average() const
{
?if (valarray<double>::size() > 0)
??return valarray<double>::sum()/valarray<double>::size();
?else
??return 0;
}
3)訪問基類對象
使用私有繼承時。該string對象沒有名稱。那么,student類的代碼怎樣訪問內部的string對象呢?答案是使用強制類型轉換。因為student類是從string類派生而來的,因此能夠通過強制類型轉換,將student對象轉換為string對象。結果為繼承而來的string對象。
const string& student::Name() const
{
?return (const string&) *this;
}
上述方法返回一個引用。該應用指向用于調用該方法的student對象中的繼承而來的string對象。
4)訪問基類的友元函數
用類名顯示地限定函數名不適合于友元函數,這是由于友元不屬于類。只是能夠通過顯示地轉換為基類來調用正確的函數。
比如,對于以下的友元函數定義:
ostream& operator << (ostream& os,const student& stu)
{
?os << "scores for " << (const string&)stu << ":\n";
?...
}
注意:引用stu不會自己主動轉換為string引用,根本原因在于。在私有繼承中。在不進行顯式類型轉換的情況下,不能將指向派生類的引用或指針賦給基類引用或指針。
三、保護繼承
保護繼承是私有繼承的變體。
保護繼承在列出基類時使用keywordprotected。
使用保護繼承時,基類的公有成員和保護成員都將成為派生類的保護成員。當從派生類派生(公有)出還有一個類時,私有繼承和保護繼承之間的主要差別便呈現出來了。
使用私有繼承時,第三代將不能使用基類的接口。這是由于基類的公有方法在派生類中將變成私有方法。使用保護繼承時,基類的公有方法在第三代中將變成受保護的,因這第三代派生類可以使用它們。
版權聲明:本文博客原創文章。博客,未經同意,不得轉載。
總結
- 上一篇: word 2010中如何创建多级目录和多
- 下一篇: ASP.Net零碎