C 多型之筆記

2021-06-21 14:55:14 字數 4080 閱讀 7678

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...