繼承方式
說明
public
基類的public和protected的成員被派生類繼承後,保持原來的狀態
private
基類的public和protected的成員被派生類繼承後,變成派生類的private成員
protected
基類的public和protected的成員被派生類繼承後,變成派生類的protected成員
注:無論何種繼承方式,基類的private成員都不能被派生類訪問。從上面的表中可以看出,宣告為public的方法和屬性可以被隨意訪問;宣告為protected的方法和屬性只能被類本身和其子類訪問;而宣告為private的方法和屬性只能被當前類的物件訪問。
1. 友元函式必須在類中進行宣告而在類外定義,宣告時須在函式返回型別前面加上關鍵字friend。友元函式雖不是類的成員函式,但它可以訪問類中的私有和保護型別資料成員。
2. 虛函式在重新定義時引數的個數和型別必須和基類中的虛函式完全匹配,這一點和函式過載完全不同。
3. #include 《檔名》和#include "檔名"
4. 陣列也可以作為函式的實參和形參,若陣列元素作為函式的實參,則其用法與變數相同。當陣列名作為函式的實參和形參時,傳遞的是陣列的位址。當進行按值傳遞的時候,所進行的值傳送是單向的,即只能從實參傳向形參,而不能從形參傳回實參。形參的初值和實參相同,而形參的值發生改變後,實參並不變化,兩者的終值是不同的。而當用陣列名作為函式引數進行傳遞時,由於實際上實參和形參為同一陣列,因此當形引數組發生變化時,實參陣列也隨之發生變化。
注:實參陣列與形引數組型別應一致,如不一致,結果將出錯;形引數組也可以不指定大小,在定義陣列時陣列名後面跟乙個空的方括號,為了在被呼叫函式中處理陣列元素的需要,可以另設乙個引數,傳遞陣列元素的個數。如:int sum(int array,int n);
5. 過載、覆蓋和隱藏的區別?
函式的過載是指c++允許多個同名的函式存在,但同名的各個函式的形參必須有區別:形參的個數不同,或者形參的個數相同,但引數型別有所不同。
覆蓋(override)是指派生類中存在重新定義的函式,其函式名、引數列、返回值型別必須同父類中的相對應被覆蓋的函式嚴格一致,覆蓋函式和被覆蓋函式只有函式體 (花括號中的部分)不同,當派生類物件呼叫子類中該同名函式時會自動呼叫子類中的覆蓋版本,而不是父類中的被覆蓋函式版本,這種機制就叫做覆蓋。
下面我們從成員函式的角度來講述過載和覆蓋的區別。
成員函式被過載的特徵有: 1) 相同的範圍(在同乙個類中);2) 函式名字相同;3) 引數不同;4) virtual關鍵字可有可無。
覆蓋的特徵有: 1) 不同的範圍(分別位於派生類與基類);2) 函式名字相同;3) 引數相同;4) 基類函式必須有virtual關鍵字。
比如,在下面的程式中:
#include
<
iostream.h
>
class
base
void
f(float
x)virtual
void
g(void)};
class
derived :
public
base
};void
main(
void
)
函式base::f(int)與base::f(float)相互過載,而base::g(void)被derived::g(void)覆蓋。
隱藏是指派生類的函式遮蔽了與其同名的基類函式,規則如下: 1) 如果派生類的函式與基類的函式同名,但是引數不同。此時,不論有無virtual關鍵字,基類的函式將被隱藏(注意別與過載混淆)。2) 如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)。
比如,在下面的程式中:
#include
<
iostream.h
>
class
base
void
g(float
x)void
h(float
x)};
class
derived :
public
base
//被繼承之後,virtual 可有可無,但最好有。繼承後,還是虛函式。
void
g(int
x)void
h(float
x)using
base::g;
//這句話是用來引用父類中被隱藏的部分的。
};
通過分析可得:
1) 函式derived::f(float)覆蓋了base::f(float)。
2) 函式derived::g(int)隱藏了base::g(float),注意,不是過載。
3) 函式derived::h(float)隱藏了base::h(float),而不是覆蓋。
看完前面的示例,可能大家還沒明白隱藏與覆蓋到底有什麼區別,因為我們前面都是講的表面現象,怎樣的實現方式,屬於什麼情況。下面我們就要分析覆蓋與隱藏在應用中到底有什麼不同之處。在下面的程式中bp和dp指向同一位址,按理說執行結果應該是相同的,可事實並非如此。
void
main(
void
)
請大家注意,f()函式屬於覆蓋,而g()與h()屬於隱藏。從上面的執行結果,我們可以注意到在覆蓋中,用基類指標和派生類指標呼叫函式f() 時,系統都是執行的派生類函式f(),而非基類的f(),這樣實際上就是完成的「介面」功能。而在隱藏方式中,用基類指標和派生類指標呼叫函式f()時,系統會進行區分,基類指標呼叫時,系統執行基類的f(),而派生類指標呼叫時,系統「隱藏」了基類的f(),執行派生類的f(),這也就是「隱藏」的由來。
過載(overload):這個好理解,在同個space域同名的。引數必須不同,有關virtual無關.
覆蓋(override):同名字,同引數,有virtual,覆蓋好理解比如show()函式,a派生了b,如果b中的show()覆蓋了a中的show(),但b中仍然有兩個show(),而不管是a類指標也好,b類物件呼叫也好,都只能呼叫b類自己的那個show();而從a類繼承過來的show()函式真的就被覆蓋了,沒有了嗎? 答案是不對的.這時可以在b類物件顯示的呼叫a類繼承過來的show();
程式**:
#include
<
iostream
>
using
namespace
std;
classa
inta;
}; class
b:publica
intb;
};int
main()
總結:通俗的講b類還是有兩個show(),只是呼叫由a繼承過來的show()只能通過顯式的呼叫方法 [類名::virtual函式名] 而不管是基類a的指標 (b b; a *p = &b; p->show())或者派生類的物件(b b; b.show()),都只能呼叫b類的自己本身存在的show()函式
隱藏hide:
1:同名同參無virtual
2:同名不同參不管有無virtual
程式**:
class
a ;
//編號1
void
rose(
inta) {}
//編號2
}; class
b:public
a ;
//編號3
void
rose(
inta,
intb) {};
//編號4
};
類b中的show()和rose()明顯是隱藏了類a的show()和rose() 隱藏的理解: b類中其實有兩個show(),兩個rose(); 但為什麼不叫過載呢?你會這樣想,但我可以告訴你,因為類b中的兩個show(),兩個rose(),不是都可以被b類的物件呼叫的.
編號1和編號2,在類b中哪怕存在,但只能通過類a的指標呼叫,而不能通過b類物件呼叫,如:
程式**:a *
p =newb;
p->
show();
p->
rose(
3);
p->
rose(3,
5);
//error
編號3和程式設計4,只能通過類b物件呼叫,而不能通過類a的指標呼叫,如:
程式**:
b b;
b.show();
b.rose(3,
5);
b.rose(
4);
//error
6. 用引數列表可以區分過載函式,為什麼返回值卻不能區分過載函式?
比如說有兩個函式:int fun(); double fun(); 如果寫fun();那麼編譯器就不知道該呼叫誰了。函式呼叫結束後才能確定返回值,但程式在呼叫函式時就需要明確知道呼叫哪乙個過載的函式,這前後矛盾。
7. 派生類與基類之間的關係
8. 靜態聯編和動態聯編
程式呼叫函式時,將使用哪個可執行**塊呢?編譯器負責回答這個問題。將源**中的函式呼叫解釋為執行特定的函式**塊被稱為函式名聯編。在c語言中,這非常簡單,因為每個函式名都對應乙個不同的函式。在c++中,由於函式過載的緣故,這項任務更複雜。編譯器必須檢視函式引數以及函式名才能確定使用哪個函式。然而,c/c++編譯器可以在編譯過程完成這種聯編。在編譯過程中進行聯編被稱為靜態聯編/繫結,又稱為早期聯編/繫結。不過,虛函式使這項工作變得更困難。因為使用哪個函式是不能在編譯時確定的,因為編譯器不知道使用者將選擇哪種型別的物件。所以,編譯器必須生成能夠在程式執行時選擇正確的虛方法的**,這被稱為動態聯編/繫結,又被稱為晚期聯編/繫結。
基類與派生類
初學c 的時候,很多人都很頭疼各種訪問標號下基類與派生類的關係,其實,死記硬背肯定不是乙個好的辦法,要知道它們之間的關係,先要分析一下訪問標號是如何產生的 在沒有繼承之前,類的只有兩類使用者 類本身和類的使用者。把類成員通過public和private劃分恰好體現了這一分割 類的使用者只能訪問類的p...
理解C 基類與派生類
通過繼承機制,可以利用已有的資料型別來定義新的資料型別。所定義的新的資料型別不僅擁有新定義的成員,而且還同時擁有舊的成員。我們稱已存在的用來派生新類的類為基類,又稱為父類。由已存在的類派生出的新類稱為派生類,又稱為子類。在c 語言中,乙個派生類可以從乙個基類派生,也可以從多個基類派生。從乙個基類派生...
C 派生類與基類的賦值
class a class b a void main 可以把派生類賦值給基類。我們知道賦值,是呼叫了類的賦值運算子。所以當派生類給基類賦值時,呼叫了基類的複製運算子函式,該函式的引數是基類物件的const 引用,那麼 a b,實際就是用基類引用派生類,然後將派生類中基類部分賦值給對應的基類成員。而...