1. 程式人生 > >(C++)淺談多型基類解構函式宣告為虛擬函式

(C++)淺談多型基類解構函式宣告為虛擬函式

主要內容:

1、C++類繼承中的建構函式和解構函式

2、C++多型性中的靜態繫結和動態繫結

3、C++多型性中解構函式宣告為虛擬函式

1、C++類繼承中的建構函式和解構函式

在C++的類繼承中,

建立物件時,首先呼叫基類的建構函式,然後在呼叫下一個派生類的建構函式,依次類推;

析構物件時,其順序正好與構造相反;

具體參考文章:http://www.cnblogs.com/AndyJee/p/4575385.html

2、C++多型性中的靜態繫結和動態繫結

物件的靜態型別:物件在宣告是採用的型別,在編譯期確定;

物件的動態型別:當前物件所指的型別,在執行期決定,物件的動態型別可以更改,但靜態型別無法更改。

靜態繫結:繫結的是物件的靜態型別,某特性(比如函式)依賴於物件的靜態型別,發生在編譯期。
動態繫結:繫結的是物件的動態型別,某特性(比如函式)依賴於物件的動態型別,發生在執行期。

具體參考文章:http://www.cnblogs.com/AndyJee/p/4575670.html

3、C++多型性中基類解構函式宣告為虛擬函式

先來看幾段程式例子:

  • 將基類解構函式宣告為虛擬函式
#include <iostream>
using namespace std;


class Person{
public:
    virtual ~Person(){  //declare destructor as a virtual function
    cout << "Person::~Person()" << endl;
    }
};

class Student : public Person{
public:
    ~Student(){     // virtual or not is OK
        cout << "Student::~Student()" << endl;
    }
};

int main(){
    Person *pt1 = new Person;
    Person *pt2 = new Student;        // base class pointer point to derived class
    // Student *pt3 = new Person;     // derived class pointer can not point to base class
    Student *pt4 = new Student;

    delete pt1;
    cout << "*********" << endl;
    delete pt2;
    cout << "*********" << endl;
    //delete pt3;
    //cout << "*********" << endl;
    delete pt4;
    cout << "*********" << endl;

    return 0;
}

執行結果:

  • 不將基類解構函式宣告為虛擬函式:
#include <iostream>
using namespace std;


class Person{
public:
    ~Person(){  //declare destructor as a virtual function
    cout << "Person::~Person()" << endl;
    }
};

class Student : public Person{
public:
    ~Student(){     // virtual or not is OK
        cout << "Student::~Student()" << endl;
    }
};

int main(){
    Person *pt1 = new Person;
    Person *pt2 = new Student;        // base class pointer point to derived class
    // Student *pt3 = new Person;     // derived class pointer can not point to base class
    Student *pt4 = new Student;

    delete pt1;
    cout << "*********" << endl;
    delete pt2;
    cout << "*********" << endl;
    //delete pt3;
    //cout << "*********" << endl;
    delete pt4;
    cout << "*********" << endl;

    return 0;
}

執行結果:

可以看出:

用基類指標指向派生類時

在基類解構函式宣告為virtual的時候,delete基類指標,會先呼叫派生類的解構函式,再呼叫基類的解構函式。

在基類解構函式沒有宣告為virtual的時候,delete基類指標,只會呼叫基類的解構函式,而不會呼叫派生類的解構函式,這樣會造成銷燬物件的不完全。

分析:

Person *pt2 = new Student;

pt2的靜態型別為Person,而動態型別為Student,

當解構函式為虛擬函式時,為動態繫結,delete pt2,會呼叫動態型別即派生類的解構函式,由於繼承關係,也會呼叫基類的解構函式;

而當解構函式為非虛擬函式時,為靜態繫結,delete pt2,會呼叫靜態型別即基類的解構函式,而不會呼叫派生類的解構函式。

(以上純屬個人理解)

總結:

  • 應該為多型基類宣告虛析構器。一旦一個類包含虛擬函式,它就應該包含一個虛析構器,因為多型性,必定會有基類呼叫派生類。

  • 如果一個類不用作基類或者不需具有多型性,便不應該為它宣告虛析構器。

參考文章:

http://www.cnblogs.com/children/archive/2012/08/13/2636956.html

相關推薦

轉載C++函式宣告虛擬函式

主要內容: 1、C++類繼承中的建構函式和解構函式 2、C++多型性中的靜態繫結和動態繫結 3、C++多型性中解構函式宣告為虛擬函式 1、C++類繼承中的建構函式和解構函式 在C++的類繼承中, 建立物件時,首先呼叫基類的建構函式,然後在呼叫下一

C++函式宣告虛擬函式

主要內容: 1、C++類繼承中的建構函式和解構函式 2、C++多型性中的靜態繫結和動態繫結 3、C++多型性中解構函式宣告為虛擬函式 1、C++類繼承中的建構函式和解構函式 在C++的類繼承中, 建立物件時,首先呼叫基類的建構函式,然後在呼叫下一個派生類的建構函式,依次類推; 析構物件時,其

C++函式宣告虛擬函式

先來看幾段程式例子:1. 將基類解構函式宣告為虛擬函式#include <iostream

為啥繼承時的析一般宣告虛擬函式

1、為啥繼承時基類的解構函式宣告為虛擬函式? 文字描述太抽象了,直接用程式碼給出答案。 (1)第一段程式碼: #include<iostream> using namespace std ; class Base { public: Base() {

學習之路:bash及其特性,命令歷史以及用戶管理及權限,shell的

bash 管理權限 過了一周了,進度似乎有點懈怠,不過過了周末重整旗鼓啦shell(外殼)GUI:Gnome,KDE,xfceCLI:sh,csh,ksh,bashbash(父進程)-----bash(子進程)他們相互獨立彼此不知命令歷史:historybash支持的引號:‘ ’命令替換(鍵盤~的按鍵

C++筆記protected

一個類使用protected關鍵字來宣告是希望與派生類分享但是不想被其他公共訪問使用的成員。所以protected可以看做public和private的中間產物 解析protected

一隻簡單的網路爬蟲基於linux C/C++————併發IO複用模型

Linux常用的併發模型 Linux 下設計併發網路程式,有典型的 Apache 模型( Process Per Connection ,簡稱 PPC ), TPC ( Thread Per Connection )模型,以及 select 模型, poll

學習之路:基礎命令及linux工作原理

linux命令 看了視頻,它系統的講解了linux從硬件到操作系統的工作過程,以及常用的基礎命令的詳細參數及用法。 我也在這裏整理之後加強記憶一次基本概念,及linux文件樹目錄的基本知識結構。 硬件——>操作系統OS——>l

學習之路:輸出重定向,grep及正則表達式,egrep

grep 地址總線:內存尋址 數據總線:傳輸數據 控制總線:控制指令 > :輸出重定向(會覆蓋原有內容) >>: 追加重定向(不會覆蓋,追加輸出) 2>: 重定向錯誤輸出 2

學習之路:三種語句結構,vim編輯器快捷鍵及使用方法,find命令使用

vim編輯器循環;forwhileuntil for 變量 in 列表; do 循環體 done e.g for I in ‘seq 1 $FILE‘ ; doecho "Hello,‘head -n $I

JAVA基礎複習繼承、、抽象和介面

1、超類也稱為父類或者基類,次類又稱為子類或者拓展類、派生類。子類從它的父類中繼承可訪問的資料域和方法,還可以新增新資料域和新方法。 2、繼承:子類並不是父類的一個子集,子類比它的父類包含更多的資訊和方法;父類中的私有資料域在該類之外是不可訪問的;不是所有是一種關係都應該用繼承來建模,但是繼承是

Effective C++筆記之七:宣告virtual函式

應該為多型基類宣告virtual解構函式,否則容易造成記憶體洩露。 因為C++明白指出,當derived class物件經由一個base class指標被刪除,而該base class如果帶有一個non-virtual解構函式,其結果未定義一實際執行時通常發生的是物件的derived成分沒

關於Java基礎的複習總結java API

鳥隨鸞鳳飛騰遠,人伴賢良品自高 API(Application Programming Interface,應用程式程式設計介面)是一些預先定義的函式,目的是提供應用程式與開發人員基於某軟體或硬體得以訪問一組例程的能力,而又無需訪問原始碼,或理解內部工作機制的細節。 一:集合框架和

關於Java基礎的複習總結異常

孩子看善惡,承認分利弊 1、Throwable Error:屬於系統級別的異常,應盡力使程式安全退出 Exception check異常:必須捕獲或者宣告丟擲 執行時異常:不要求必須捕獲或者宣告丟擲 2、異常處理機制 程式中預先設定好對付異常的處理方法----》程式執行------

關於Java基礎的複習總結面向物件特徵

種下一棵樹,最好的時間是十年前,其次就是現在 面向物件三大特徵 封裝:保證物件自身資料的完整性和安全性 繼承:建立類之間的關係,實現程式碼複用,方便系統擴充套件 多型:相同的方法呼叫,不同的實現方式 PS:抽象也是面向物件思想重要部分,但因為各種程式語言都使用抽象,所以,不能算java

PKI學習之路-----------------------socket

首先為什麼要用socket? 如果沒有socket,我們傳輸資料需要藉助TCP/IP協議,不僅需要三次握手,還要友好分手,每次傳輸都要經過複雜的連線,具體傳輸過程中,也會有一大堆的問題,什麼滑動視窗,什麼累計確認,分組快取,流量控制,,,聽著就頭皮發麻,而socket就是TCP/IP的實現

【深入Java虛擬機器5】:性實現機制—靜態分派與動態分派

方法解析 Class檔案的編譯過程中不包含傳統編譯中的連線步驟,一切方法呼叫在Class檔案裡面儲存的都只是符號引用,而不是方法在實際執行時記憶體佈局中的入口地址。這個特性給Java帶來了更強大的動態擴充套件能力,使得可以在類執行期間才能確定某些目標方法的直接引

effective c++乾貨之條款07:宣告virtual函式

1. 避免記憶體洩漏 首先,我們實現一個多型: class CPeople { public: CPeople(){} virtual ~CPeople(){} }; class CChinese:public CPeople { public:

深度優先搜尋DFS

一,定義         一個人走進了迷宮,到達甲路口時,他面前有Ñ條路,他選擇了其中的一條,走了一會後到達乙路口,面前又出現Ñ條路,他又選擇了其中的一條,走了一會發現走不通,於是他退回到乙路口又

讀書筆記《Effective c++》 條款07 宣告virtual函式

這個其實不用多說,用過OO類的語言應該都要這樣。 這麼看來簡單的物件和delphi的物件結構差不多。 書中說c++不支援final,在c++11中已經支援了,所以如果不希望類被繼承,可以加上final c++的final有兩個用途: 1.阻止類被繼承 2.組織虛擬函式被