C/C++学习----第二章 继承和派生
第二章 繼承和派生
2.1 派生
派生類或派生類的使用者均不能訪問基類的私有數據成員;對于基類的公有成員的訪問,如果派生的方式不同,訪問的權限也不同。派生時,不指明派生類型的,按私有派生進行派生。
<1>私有派生
由私有派生得到的派生類,對基類的公有成員只能是私有繼承,也就是基類的所有公有成員只能成為派生類的私有成員,這些私有成員只能被派生類的成員函數訪問,派生類的使用者無權訪問。此時,基類中的保護段成員也成為派生類的私有成員。
如果希望基類中的某些公有成員、保護成員在私有派生類中也是公有、保護的,使得派生類和派生類的使用者可以訪問它,則可以在派生類中的公有段或保護段中說明這些成員,并在成員名前綴上“類名::”。
class A {
??? int count;
public:
??? A(int i = 0){
?????? count = i; }
??? int getCount(){
?????? return count; }
};
?
class B :A{ //私有派生
public:
??? A::getCount; //聲明基類的公有成員為派生類的公有成員
/*protected:
??? A::getCount; */ //聲明基類的公有成員為派生類的保護成員
};
?
void main()
{
??? B b;??
??? int num = b.getCount();
}
聲明基類的公有成員為派生類的公有成員,只需要注明類名和函數名,不需要聲明函數參數和返回值,因為該函數在基類中已經聲明過。
私有段中不能進行聲明。派生類中有與基類相同的函數時,這種聲明是無效的,派生對象調用的函數是派生類中的,而不是基類的。在派生類公有段中聲明基類的構造函數,如果基類構造函數(重載情況下)同在公有段中,則基類的構造函數成為派生類中的公有成員;如果基類構造函數處于不同的段中,系統將根據派生類構造函數調用基類構造函數的使用,決定這種聲明的有效性。
?
| Class A { protected: ??? int count; ??? void print1(); public: ??? int num; ??? void print(); ??? A(); ??? A(int i); }; ? class B: A{ protected: ??? A::count; ??? A::print1; public: ??? B(); ??? void print(); ??? //A::count; //error不能同時聲明 ??? A::A;? ??? A::num; ??? A::print; //聲明無效 }; | class A { protected: ??? A(int i); public:??? ??? A(); }; ? class B: A{ public: ??? B():A(){ ??? } ??? A::A;? //public段A()有效 /* B():A(2){ ??? } ??? A::A;? */ //protected段A()有效 }; ? |
<2>公有派生
通過公有派生得到派生類,基類中的公有成員在派生類中仍然是公有成員,基類中的保護段成員在派生類中仍然是保護成員。
<3>保護派生
通過公有派生得到派生類,基類中的公有成員和保護段成員,在派生類中是保護成員。
2.2 派生類的構造函數和析構函數
2.2.1派生類構造函數和析構函數的定義原則
在以下情況下必須定義派生類的構造函數
??? <1>派生類本身需要構造函數
<2>在定義派生類對象時,其相應的基類需要調用帶參數的構造函數。
構造函數格式:
派生類構造函數(參數):基類構造函數(參數),對象成員1構造函數(參數),。。。對象成員n構造函數(參數) { //基類和對象成員構造函數的排放順序不分先后
}
如果基類使用缺省的構造函數或不帶參數的構造函數,則在派生類中定義構造函數時可略去“:基類構造函數(參數)”;如果派生類對象不需要初始化,也不必定義構造函數。
?
派生類的析構函數的定義與基類沒有關系。
如果基類、成員類和派生類都有構造函數,執行順序分別是先基類、再對象成員、后派生;析構函數時的執行順序正好相反,先派生、再對象成員、后基類。
class A {
??? int count;
public:
??? A(int i = 0){
?????? count = i;
??? }
?????? ~A(){
??? }
};
?
class B{
public:
??? B(char *str){
?????? memset(s, 0, 20);
?????? strcpy(s, str);
??? }
~B(){
??? }
private:
??? char s[20];
};
?
class C :A{
public:
??? C(int num);
~C(){
??? }
private:
??? int number;
??? B b;
};
C::C(int num):b("CHINA"),A(num){
??? number = num;
}
void main(void )
{
??? C c(100);? //先A(num),再b("CHINA"),最后C::C(int num)
} //析構時,先~C(),再~B(),最后~A()
2.2.2虛析構函數:
c++語言標準關于虛析構函數的闡述:當通過基類的指針去刪除派生類的對象,而基類又沒有虛析構函數時,結果將是不可確定的。實際運行時經常發生的是,派生類的析構函數永遠不會被調用。聲明析構函數為虛就會調用基類和派生類的析構函數。
#include <iostream.h>
class Base
{
? public:
??? virtual ~Base() { cout<< "~Base" << endl ; }
};
class Derived : public Base
{
? public:
??? virtual ~Derived() { cout<< "~Derived" << endl ; }
};
?
void main(void)
{
??? Base * pB = new Derived;? // upcast
??? delete pB; //對象內存釋放時,Derived和Base的析構函數都會被調用。
}
輸出結果為:
??? ~Derived
??? ~Base
如果析構函數不為虛,那么輸出結果為
~Base
2.3 派生類對基類私有成員的訪問
在公有派生和私有派生中,繼承類都不能直接訪問基類的私有成員。繼承類訪問基類的私有成員的方法有以下兩種方法:
<1>在基類中增加保護類成員
將基類私有成員中需要提供給派生類訪問的部分定義為保護段成員。基類的保護類成員可以被派生類(無論公有派生、保護派生還是私有派生)訪問,但外界對象不能訪問。
class A {
protected:
??? int count;
public:
??? A(int i = 0){
?????? count = i;
??? }
??? void print(){
?????? cout << count;
??? }
};
?
class B:public A{
??? int num;
public:
??? B(int i){ num = i;}
??? void print(){
?????? cout << count << " " << num; //公有繼承派生類訪問基類的保護成員
??? }
};
?
class C :B{
public:
??? C(): B(10){ }
??? void print(){
?????? cout << count; //私有繼承的派生類訪問基類的保護成員
??? ??? //cout << num; //私有繼承的派生類不能訪問基類的私有成員
??? }
};
?
void main()
{
??? B b(4);
??? C c;??
??? b.print();
??? c.print();
}
?
<2>將需要訪問基類私有成員的派生類成員函數聲明為基類的友元
在基類中增加保護類成員的方法,存在一個弊端,多重公有繼承或保護繼承得到的派生類,仍然可以訪問原基類的保護段成員。可以通過將需要訪問基類私有成員的派生類成員函數聲明為基類的友元的方法,使得派生類中的指定成員函數函數可以訪問基類的私有成員,其他的成員函數則不能訪問基類的私有成員。
通過友員訪問基類的私有成員,這種訪問不是經常的,但是必要的。否則,需要類提供足夠的成員函數。友元的使用使得C++中的數據封裝性受到削弱,導致程序的維護性變差(慎用)。
??? 聲明為某個類的友元的外界對象既可以是另一個類的成員函數,也可以是不屬于任何類的一個函數,還可以是某個類(此時,該類中的所有成員函數都成為友元)。設置友元的首要目的是可以使友元函數訪問(使用或改變)某類的私有成員。
??? 友元的聲明可以放在類的公有部分,也可以放在類的私有部分。
??? class circle;
class point {
??? int x, y;
public:
??? point(int x, int y);
??? friend void print(const point p); //聲明不屬于任何類的函數為友元函數
??? friend class circle; //聲明某類.為友元類
??? friend void circle::getCircleCenter(int &x, int &y); //聲明某類的函數為友元函數,該函數可以訪問point的私有成員x和y
}
?
說明:友元函數雖然可以訪問類對象的私有成員,但是它沒有this指針,在某一時刻究竟是應該訪問哪一個對象的私有成員,很難確定。可以通過向友元函數傳遞對象的辦法,顯式地確定對象。
友元關系是“給予”的,而不是“索取”的。也就是說,如果類B是類A的友元類,類A中必須聲明類B是類A的友元類。友元關系是不對稱且不傳遞的。
?
2.4 虛基類
| P part(of A) ? ? P part(of B) ? ? C part |
| C |
| A |
| B |
| P |
| P |
| C |
| A |
| B |
| P |
??? 在如下左圖所示的多層繼承類中,類P兩次成為類C的間接基類,此時,C類對象中有兩個類P的對象:由A繼承的P和由B繼承的P,C類對象的內存排列如中圖所示:
??? 虛基類:當在多條繼承路徑上有一個公共的基類,在這些路徑中的某幾條路徑匯合處,這個公共基類會產生多個實例,如果需要只保存基類的一個實例,可以將這個公共基類聲明為虛基類。虛基類的聲明如下表右側所示:
| 非虛基類的多重繼承 class P { public: ??? int next; }; class A: public P { }; class B: public P { }; class C: public A, public B { public: ??? void set( int i); }; void C::set(int i) { ??? next = i;? //具有二義性 } ? | 虛基類的多重繼承 class P { public: ??? int next; }; class A: virtual public P { }; class B: virtual public P { }; class C: public A, public B { public: ??? void set( int i); }; void C::set(int i) { ??? next = i;? //無二義性 } ? |
?
虛基類構造函數的調用規則:
<1>同一層次中虛基類的構造函數在非虛基類之前調用
<2>同一層次中包含多個虛基類,虛基類構造函數按照他們的說明順序調用
<3>若虛基類由非虛基類派生,則遵守先調用基類構造函數,再調用派生類構造函數。
??? 例:
| base2類 |
| base2類 |
| base虛基類 |
| level1類 |
| level2虛基類 |
| toplevel類 |
如下所示的類繼承關系:
?
建立toplevel類對象top時,構造函數的調用順序是:
base類
base2類
level2類
base2類
level1類
toplevel類
?轉載于:https://www.cnblogs.com/java201408/archive/2006/10/27/3901062.html
總結
以上是生活随笔為你收集整理的C/C++学习----第二章 继承和派生的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 即将步入2020年,程序员如何在新的一年
- 下一篇: PDF 合并软件要收费?程序员自己做一个