1.繼承型別(參考部落格:
私有繼承,公有繼承,和保護繼承三種,主要是子類在類內,類外使用基類的成員的許可權不同。
例如,基類a,b繼承a,c繼承b
b繼承a的方式有兩方面的影響:
①b在類內、類外使用a成員的許可權
②c在類內、類外使用a成員的許可權
測試**如下:
class a
;class b :public a
void setprotected(int nprotected)
void setprivate(int nprivate)
};b b; //建立b類的物件c
b.m_public = 100; //正確
b.m_protected = 100; //錯誤,public繼承中基類的protected在派生類中是protected
b.m_private = 100; //錯誤,在派生類中都不可以直接使用,在類外就更不能了
class c :protected a
void setprotected(int nprotected)
void setprivate(int nprivate)
};c c; //建立c類的物件c
c.m_public = 100; //錯誤,protected繼承c類裡變成了protected成員
c.m_protected = 100; //錯誤,protected繼承c類裡還是protected成員
c.m_private = 100; //錯誤,在派生類中都不可以直接使用,在類外就更不能了
class d :private a
void setprotected(int nprotected)
void setprivate(int nprivate)
};d d; //建立d類的物件d
d.m_public = 100; //錯誤,private繼承d類裡變成了private成員
d.m_protected = 100; //錯誤,private繼承d類裡變成了private成員
d.m_private = 100; //錯誤,在派生類中都不可以直接使用,在類外就更不能了
分析:①a的公有成員和保護成員在b中許可權不變,即在b類內均可訪問,在類外不可訪問a的保護成員
②a的公有成員和保護成員在c中變為保護成員屬性,即在c類內均可訪問,在類外不可訪問
③a的公有成員和保護成員在d中均變為私有成員屬性,訪問同2;
class e :public b
void setprotected(int nprotected)
void setprivate(int nprivate)
};e e; //建立e類的物件e
e.m_public = 100; //正確
e.m_protected = 100; //錯誤,protected繼承e類裡變成了protected成員
e.m_private = 100; //錯誤,在派生類中都不可以直接使用,在類外就更不能了
class f :public c
void setprotected(int nprotected)
void setprivate(int nprivate)
};f f; //建立f類的物件f
f.m_public = 100; //錯誤,在c類裡就已變成protected成員
f.m_protected = 100; //錯誤,protected繼承e類裡變成了protected成員
f.m_private = 100; //錯誤,在派生類中都不可以直接使用,在類外就更不能了
class g :public d
void setprotected(int nprotected)
void setprivate(int nprivate)
};
分析:①繼承方式對類內的影響體現了,私有繼承時,在g中類內類外均不可訪問
2.多型性呼叫
多型性呼叫分為兩種:靜態繫結(即函式過載)和動態繫結(虛函式),也有人稱為編譯時多型和執行時多型。本來過載和覆蓋很好區別,但是c++的隱藏規則,很容易使人迷惑。
①多型性(晚繫結)的使用基礎是賦值相容,而賦值相容成立的條件是公有繼承,因此,只有公有繼承方式才能實現執行時多型
②虛函式語法:
基類:virtual 返回值型別 函式名(引數列表);
派生類:(virtual)可以省略,函式名和引數列表同基類完全一致,即通過覆蓋實現多型;若引數列表不一致,則為過載,就會產生隱藏,不能實現多型的效果。
③虛函式的實現原理
在包含虛函式的類中,編譯器都會**的定義乙個指標,指向虛表,虛表中存放的是虛函式的偏移量而非位址
表中虛函式的位置與基類中虛函式的宣告順序一致
虛表指標大小為4位元組
若子類對基類中的虛函式沒有覆蓋,則在虛表中存放的就是基類虛函式 的位址
④多型性呼叫的實現(與指標型別無關,而與指向的物件有關)
例程:
#includeusing namespace std;
class a
virtual void fun() };
class b : public a
void fun() };
int main(void)
第乙個p->foo()和p->fuu()都很好理解,本身是基類指標,指向的又是基類物件,呼叫的都是基類本身的函式,因此輸出結果就是1、2。
第二個輸出結果就是1、4。p->foo()和p->fuu()則是基類指標指向子類物件,正式體現多型的用法;
還有一種呼叫,是定義子類指標,指向基類,是不安全的,因此需要進行強制型別轉換
b *ptr = (b *)&a; ptr->foo(); ptr->fun();
呼叫結果為3 2
從上面明顯可以看出,多型性呼叫可指標型別無關,只和指向的物件有關;而隱藏規則恰恰相反,和指向的物件無關,只和指標的型別相關;接下來就分析隱藏規則。
3.隱藏規則
例程
//小結:1、有virtual才可能發生多型現象
// 2、不發生多型(無virtual)呼叫就按原型別呼叫
#includeusing namespace std;
class base
出現隱藏的情況:
①子類的引數列表和基類的不一致,無論該函式是否有virtual關鍵字,基類的函式將被子類的隱藏,即呼叫時和指向的物件無關,和指標型別相關,區別與過載
②子類的引數列表和基類一致,但無virtual關鍵字,基類的函式將被子類隱藏,區別與覆蓋
4.直接定義物件,而不用指標呼叫成員函式,那就很簡單;只是不能體現多型性
5.析構函式可以定義為虛函式,建構函式不能定義為虛函式
析構函式定義為虛函式的作用,參考部落格例程
#include "stdafx.h"
#include #include class graph
;graph::graph(double x,double y)
void graph::showarea()
呼叫結果為:
呼叫圖形類析構函式
沒有析構rectangle物件,將基類析構函式定義為虛析構函式,則可解決問題
雖然派生類的析構函式與基類的析構函式名字不同,但是如果將基類的析構函式定義為虛函式,由該基類派生而來的所有派生類的析構函式都自動成為虛函式。
最後,記錄一下this指標的理解
在mfc中,cwnd::oncreate()中呼叫了this->precreatewindow();
一直以為this指標是指向cwnd的,總也不能理解為什麼呼叫的是子類的precreatewindow();其實this指標指向的是例項化物件,cwnd並未例項化,因此指向的是其派生類物件,因此就完全可以理解了
c 筆記 多型
編譯時的多型是通過靜態連編來實現的 執行時的多型是通過動態連編來實現的 利用虛函式機制,c 可部分地採用動態連編 在c 中,編譯時的多型性主要是通過函式過載和運算子過載實現的,執行時多型性主要是通過虛函式來實現的 virtual 返回型別 函式名 形參表 在基類中的某個成員函式被宣告為虛函式後,此虛...
c 多型筆記
if語句或switch語句會帶來混亂,且不遵守設計模式中的 開閉原則 開閉原則指的是 對擴充套件開放,對修改關閉 用多型 同乙個介面,使用不同的例項而執行不同操作 條件語句 public class test if command drivecommand.stop switch command p...
C 學習筆記 多型
引言 1.虛繼承 如果乙個派生類從多個基類派生,而這些基類又有乙個共同的基類,則在對該基類中宣告的名字進行訪問時,可能產生二義性。解決方案 虛繼承宣告,加乙個virtual 關鍵字 2.物件導向新需求 編譯器的做法不是我們期望的 如果用父類指標指向子類物件,再呼叫print 方法,均會呼叫父類中的p...