1. 程式人生 > >C++中類的多型與虛擬函式

C++中類的多型與虛擬函式

工作了好多年,才想起來寫一點筆記,我也是醉了。。。
馬上面臨面試,所以複習一下知識點,好多要點,畢竟這是個看面試不看工作能力給工資的時代=。=

面嚮物件語言的基本特性:

  1. 封裝:將客觀事物抽象成類,每個類對自身的資料和方法實行protection(private, protected,public)
  2. 繼承:廣義的繼承有三種實現形式:實現繼承(指使用基類的屬性和方法而無需額外編碼的能力)、可視繼承(子窗體使用父窗體的外觀和實現程式碼)、介面繼承(僅使用屬性和方法,實現滯後到子類實現)。
  3. 多型:系統能夠在執行時,能夠根據其型別確定呼叫哪個過載的成員函式的能力,稱為多型性。
//例程1  
#include <iostream> using namespace std; class Vehicle { public: Vehicle(float speed,int total) { Vehicle::speed=speed; Vehicle::total=total; } void ShowMember() { cout<<speed<<"|"<<total<<endl; } protected
: float speed; int total; }; class Car:public Vehicle { public: Car(int aird,float speed,int total):Vehicle(speed,total) { Car::aird=aird; } void ShowMember() { cout<<speed<<"|"<<total<<"|"<<aird<<endl; } protected
: int aird; }; void main() { Vehicle a(120,4); a.ShowMember(); Car b(180,110,4); b.ShowMember(); cin.get(); }

C++中允許派生類過載基類成員函式,對於過載來說,不同的類物件呼叫相應的成員函式,即系統知道a.ShowMember()呼叫的是Vehicle的成員方法,b.ShowMember()呼叫的是Car的成員方法。

但是實際使用中,會遇到這樣的情況:

//例程2  
#include <iostream>      
using namespace std;    

class Vehicle  
{    
public:    
    Vehicle(float speed,int total)  
    {  
        Vehicle::speed=speed;  
        Vehicle::total=total;  
    }  
    void ShowMember()  
    {  
        cout<<speed<<"|"<<total<<endl;  
    }  
protected:    
    float speed;  
    int total;  
};    
class Car:public Vehicle    
{    
public:    
    Car(int aird,float speed,int total):Vehicle(speed,total)    
    {    
        Car::aird=aird;    
    }  
    void ShowMember()  
    {  
        cout<<speed<<"|"<<total<<"|"<<aird<<endl;  
    }  
protected:    
    int aird;  
};    

void test(Vehicle &temp)  
{  
    temp.ShowMember();  
}  

void main()    
{  
    Vehicle a(120,4);  
    Car b(180,110,4);  
    test(a);  
    test(b);  
    cin.get();  
}

在這種情況下,因為Vehicle是基類,所以Car類包含了Vehicle的所有屬性和方法,所以test()呼叫是沒有問題的,但是我們想要實現的效果是傳入不同的物件呼叫對應物件類的方法,但是實際上這個例子中,系統分不清你傳給test()的是哪個類的物件,所以他們都會呼叫基類的ShowMember()函式。

為了解決這個問題,就要用到多型來解決這個問題了:對於例程式1,這種能夠在編譯時就能夠確定哪個過載的成員函式被呼叫的情況被稱做先期聯編(early binding),而在系統能夠在執行時,能夠根據其型別確定呼叫哪個過載的成員函式的能力,稱為多型性,或叫滯後聯編(late binding)

//例程3  
#include <iostream>      
using namespace std;    

class Vehicle  
{    
public:    
    Vehicle(float speed,int total)  
    {  
        Vehicle::speed = speed;  
        Vehicle::total = total;  
    }  
    virtual void ShowMember()//虛擬函式  
    {  
        cout<<speed<<"|"<<total<<endl;  
    }  
protected:    
    float speed;  
    int total;  
};    
class Car:public Vehicle    
{    
public:    
    Car(int aird,float speed,int total):Vehicle(speed,total)    
    {    
        Car::aird = aird;    
    }  
    virtual void ShowMember()//虛擬函式,在派生類中,由於繼承的關係,這裡的virtual也可以不加  
    {  
        cout<<speed<<"|"<<total<<"|"<<aird<<endl;  
    }  
public:    
    int aird;  
};  

void test(Vehicle &temp)  
{  
    temp.ShowMember();  
}  

int main()    
{    
    Vehicle a(120,4);  
    Car b(180,110,4);  
    test(a);  
    test(b);  
    cin.get();  
}

C++中的多型依賴於虛擬函式,關鍵字virtual;而java中用到的是abstract;
只要基類宣告是virtual,那麼子類就無需再聲明瞭,系統會自動新增該關鍵字,但是為了可讀性最好還是寫上吧。

虛擬函式定義需要遵循一下幾個規則:

  1. 如果虛擬函式在基類與派生類中出現,僅僅是名字相同,而形式引數不同,或者是返回型別不同,那麼即使加上了virtual關鍵字,也是不會進行滯後聯編的。
  2. 只有類的成員函式才能說明為虛擬函式,因為虛擬函式僅適合用與有繼承關係的類物件,所以普通函式不能說明為虛擬函式。
  3. 靜態成員函式不能是虛擬函式,因為靜態成員函式的特點是不受限制於某個物件。
  4. 內聯(inline)函式不能是虛擬函式,因為行內函數不能在執行中動態確定位置。即使虛擬函式在類的內部定義,但是在編譯的時候系統仍然將它看做是非內聯的。
  5. 建構函式不能是虛擬函式,因為構造的時候,物件還是一片未定型的空間,只有構造完成後,物件才是具體類的例項。
  6. 解構函式可以是虛擬函式,而且通常聲名為虛擬函式。

解構函式為什麼也要宣告為虛擬函式:

#include "stdafx.h"

#include <iostream>    

using namespace std;   



class Vehicle 

{   

public:  

    Vehicle(float speed,int total) 

    { 

        Vehicle::speed=speed; 

        Vehicle::total=total; 

    } 

    virtual void ShowMember() 

    { 

        cout<<speed<<"|"<<total<<endl; 

    } 

    virtual ~Vehicle() 

    { 

        cout<<"載入Vehicle基類解構函式"<<endl; 

        cin.get(); 

    } 

protected:   

    float speed; 

    int total; 

};   

class Car:public Vehicle   

{   

public:   

    Car(int aird,float speed,int total):Vehicle(speed,total)   

    {   

        Car::aird=aird;   

    } 

    virtual void ShowMember() 

    { 

        cout<<speed<<"|"<<total<<"|"<<aird<<endl; 

    } 

    virtual ~Car() 

    { 

        cout<<"載入Car派生類解構函式"<<endl; 

        cin.get(); 

    } 

protected:   

    int aird; 

};   



void test(Vehicle &temp) 

{ 

    temp.ShowMember(); 

} 

void DelPN(Vehicle *temp) 

{ 

    delete temp; 

} 

void main() 

{   

    Car *a=new Car(100,1,1); 

    a->ShowMember(); 

    DelPN(a); 

    cin.get(); 

}

從上例程式碼的執行結果來看,當呼叫DelPN(a);後,在析構的時候,系統成功的確定了先呼叫Car類的解構函式,而如果將解構函式的virtual修飾去掉,再觀察結果,會發現析構的時候,始終只調用了基類的解構函式,由此我們發現,多型的特性的virtual修飾,不單單對基類和派生類的普通成員函式有必要,而且對於基類和派生類的解構函式同樣重要。

相關推薦

Python虛擬函式

   C++中的虛擬函式與多型,是很多C++面向物件程式設計的一個基礎,在Python中,是否也存在多型和虛擬函式,答案是有的。看下面的這個例子 from abc import ABCMeta, abstractmethod class Base(): __m

C++虛擬函式

工作了好多年,才想起來寫一點筆記,我也是醉了。。。 馬上面臨面試,所以複習一下知識點,好多要點,畢竟這是個看面試不看工作能力給工資的時代=。= 面嚮物件語言的基本特性: 封裝:將客觀事物抽象成類,每個類對自身的資料和方法實行protection(priv

C++學習筆記 (六) ---- 虛擬函式

①、多型的概念 先上一個示例 #include <iostream> using namespace std; //基類People class People{ public: People(char *name, int age); void display(

C++ 虛擬函式

多型按字面的意思就是多種形態。當類之間存在層次結構,並且類之間是通過繼承關聯時,就會用到多型。C++ 多型意味著呼叫成員函式時,會根據呼叫函式的物件的型別來執行不同的函式。下面的例項中,基類 Shape 被派生為兩個類,如下所示: #include <iostream> usin

C++學習筆記 (六) ---- C++虛擬函式

①、多型的概念 先上一個示例 #include <iostream> using namespace std; //基類People class People{ public: People(char *name, int age); voi

C++的虛擬函式

多型的作用:繼承是子類使用父類的方法,而多型則是父類使用子類的方法。 在C++中,多型有兩種,一種是函式過載,一種是虛擬函式。函式過載發生在編譯的時候,它的函式引數是不一樣的。而虛擬函式是發生在執行的時候,它的函式原型是一樣的,依靠的是指標的指向。 有一篇非常好的文章介紹

C++ 虛擬函式

多型是指使用相同的函式名來訪問函式不同的實現方法,即“一種介面,多種方法”,用相同的形式訪問一組通用的運算,每個運算可能對應的行為不同。 C++支援編譯時多型和執行時多型,運算子過載和函式過載就是編譯時多型,而派生類和虛擬函式實現執行時多型。 執行時多型的基礎是基類指標,基

繼承虛擬函式及對的理解

    B是A的子類,子類會繼承父類的public方法,子類物件可以呼叫父類的public介面,但是子類和父類函式重名時,父類的方法會被子類覆蓋(隱藏),子類呼叫和父類同名同參函式或者過載父類的函式後不可以直接呼叫父類函式,需要加A::fun()呼叫,父類的protect方

虛擬函式-程式設計題#2(C++程式設計第6周)

程式設計題#2 來源: POJ (Coursera宣告:在POJ上完成的習題將不會計入Coursera的最後成績。) 注意: 總時間限制: 1000ms 記憶體限制: 65536kB 描述 下面

C++: 繼承和(二)虛擬函式

C++多型 多型的基礎:動態繫結 基類指標(同引用) 指向一系列的派生類物件,通過指標呼叫派生類物件的同名覆蓋方法,指標指向誰,就會呼叫誰的方法 虛擬函式表     虛擬函式的呼叫 在成員函式中呼叫虛擬函式  

C++的組合建構函式

首先看看建構函式的概念。在程式執行過程中,當遇到物件宣告語句時,程式會想作業系統申請一定的記憶體空間用於存放新建的物件。而編譯器不知道如何產生程式碼來實現初始化。所以C++做了一套物件初始化的機制,就是建構函式。 然後是類的組合中,當建立類的物件時,如果這個類

c++虛表指標虛擬函式詳解

1.c++類中的過載 看看下面的程式碼: #include <iostream> using namespace std; class Vehicle

虛擬函式

1.何為多型???多型的作用?? 多型的概念: 一個介面,多種方法 封裝的作用: 封裝可以是得程式碼模組化;繼承可以擴充套件已經存在的程式碼,都是為了代程式碼重用; 多型的目的:介面重用 2.靜態聯編和動態聯編分別表示什麼? 在編譯的

C++實現之虛擬函式虛表指標

1、靜多型與命名傾軋,動多型與虛擬函式: (1)概述: 我們知道,C++的多型有靜多型(Static polymorphism)與動多型(Dynamic polymorphism)之分,靜多型是依靠函式過載(function overloading)實現的,

C++的的繼承,虛擬函式

首先繼承,多型,虛擬函式,我們先了解一下各位的關係。 繼承是子類繼承父類,完成基礎功能的獲取,當然繼承有三種許可權,public,protect和private,如果不加許可權限定,預設繼承是私有繼承。 許可權表如下: 所以可以看到凡私有成員,子類都不能用,不過有方法能用,這裡不討

C++虛擬函式怎麼回答

1.定義:       多型性可以簡單地概括為“一個介面,多種方法”,程式在執行時才決定呼叫的函式,它是面向物件程式設計領域的核心概念。多型(polymorphism),字面意思多種形狀。   C++多型性是通過虛擬函式來實現的,虛擬函式允許子類重新定義成員函式,而子類重新

C++虛擬函式虛擬函式表,純虛擬函式

1、多型性   指相同物件收到不同訊息或不同物件收到相同訊息時產生不同的實現動作。   C++支援兩種多型性:編譯時多型性,執行時多型性。    a、編譯時多型性:通過過載函式實現 ,模板(2次編譯)   b、執行時多型性:通過

c++繼承和組合,虛擬函式c++後期繫結的本質)

組合和繼承,實現了程式碼的可擴充套件性和相容性。 多型是在虛擬函式上得到了支援。 多型的原理,函式的呼叫繫結: 把函式的呼叫和函式體相關聯稱為捆綁。當捆綁是在程式執行之前完成的,稱為早期捆綁。c語言只支援早期繫結。晚期捆綁,物件通過自身得到類的資訊,然後找

C++、單繼承、繼承、菱形繼承、菱形虛擬繼承

C++中的繼承體系,有單繼承、多繼承、菱形繼承、菱形虛擬繼承,以及各型別的物件模型,我們今天做一個簡單的剖析 (1)什麼多型? 所謂多型,就是“多種形態”。在面向物件的方法中一般是這樣描述多型的:向不同的物件傳送同一個訊息,不同的物件在接收時會產生不同的行為(即方法)。 多

c#

多型:不同的物件收到相同的訊息時,會產生不同的行為多型的兩種體現形式1.重寫父類方法1>使用new關鍵字,隱藏父類方法public class Person{ public void Show() { Console.WriteLine("我是人別害怕"); }}public class Teacher