程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 詳解C++編程中的虛函數

詳解C++編程中的虛函數

編輯:關於C++

詳解C++編程中的虛函數。本站提示廣大學習愛好者:(詳解C++編程中的虛函數)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解C++編程中的虛函數正文


我們曉得,在統一類中是不克不及界說兩個名字雷同、參數個數和類型都雷同的函數的,不然就是“反復界說”。然則在類的繼續條理構造中,在分歧的條理中可以湧現名字雷同、參數個數和類型都雷同而功效分歧的函數。

人們提出如許的假想,可否用統一個挪用情勢,既能挪用派生類又能挪用基類的同名函數。在法式中不是經由過程分歧的對象名去挪用分歧派生條理中的同名函數,而是經由過程指針挪用它們。例如,用統一個語句“pt->display( );”可以挪用分歧派生條理中的display函數,只需在挪用前給指針變量 pt 賦以分歧的值(使之指向分歧的類對象)便可。

打個比喻,你要去某一處所做事,假如乘坐公交車,必需事前肯定目標地,然後乘坐可以或許達到目標地的公交車線路。假如改成乘出租車,就簡略多了,不用查行車道路,由於出租車甚麼處所都能去,只需在上車後暫時告知司機要到哪裡便可。假如想拜訪多個目標地,只需在達到一個目標地後再告知司機下一個目標地便可,明顯,“打的”要比乘公交車 便利。不管到甚麼處所去都可以乘同—輛出租車。這就是經由過程統一種情勢能到達分歧目標的例子。

C++中的虛函數就是用來處理這個成績的。虛函數的感化是許可在派生類中從新界說與基類同名的函數,而且可以經由過程基類指針或援用來拜訪基類和派生類中的同名函數。

請剖析上面這個例子。這個例子開端時沒有應用虛函數,然後再評論辯論應用虛函數的情形。

[例] 基類與派生類中有同名函數。鄙人面的法式中Student是基類,Graduate是派生類,它們都有display這個同名的函數。

#include <iostream>
#include <string>
using namespace std;
//聲明基類Student
class Student
{
public:
  Student(int, string,float); //聲明結構函數
  void display( );//聲明輸入函數
protected: //受掩護成員,派生類可以拜訪
  int num;
  string name;
  float score;
};
//Student類成員函數的完成
Student::Student(int n, string nam,float s)//界說結構函數
{
  num=n;
  name=nam;
  score=s;
}
void Student::display( )//界說輸入函數
{
  cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\n\n";
}
//聲明公用派生類Graduate
class Graduate:public Student
{
public:
  Graduate(int, string, float, float);//聲明結構函數
  void display( );//聲明輸入函數
private:float pay;
};
// Graduate類成員函數的完成
void Graduate::display( )//界說輸入函數
{
  cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\npay="<<pay<<endl;
}
Graduate::Graduate(int n, string nam,float s,float p):Student(n,nam,s),pay(p){}
//主函數
int main()
{
  Student stud1(1001,"Li",87.5);//界說Student類對象stud1
  Graduate grad1(2001,"Wang",98.5,563.5);//界說Graduate類對象grad1
  Student *pt=&stud1;//界說指向基類對象的指針變量pt
  pt->display( );
  pt=&grad1;
  pt->display( );
  return 0;
}

運轉成果以下:

num:1001(stud1的數據)
name:Li
score:87.5

num:2001 (grad1中基類部門的數據)
name:wang
score:98.5

假設想輸入grad1的全體數據成員,固然也能夠采取如許的辦法:經由過程對象名挪用display函數,如grad1.display(),或許界說一個指向Graduate類對象的指針變量ptr,然後使ptr指向gradl,再用ptr->display()挪用。這固然是可以的,然則假如該基類有多個派生類,每一個派生類又發生新的派生類,構成了統一基類的類族。每一個派生類都有同名函數display,在法式中要挪用統一類族中分歧類的同名函數,就要界說多個指向各派生類的指針變量。這兩種方法都不便利,它請求在挪用分歧派生類的同名函數時采取分歧的挪用方法,正好像後面所說的那樣,到分歧的目標地要乘坐指定的分歧的公交車,逐個 對應,不克不及弄錯。假如可以或許用統一種方法去挪用統一類族中分歧類的一切的同名函數,那就行了。

用虛函數就可以順遂地處理這個成績。上面對法式作一點修正,在Student類中聲明display函數時,在最左面加一個症結字virtual,即

  virtual void display( );


如許就把Student類的display函數聲明為虛函數。法式其他部門都不修改。再編譯和運轉法式,請留意剖析運轉成果:

num:1001(stud1的數據)
name:Li
score:87.5

num:2001 (grad1中基類部門的數據)
name:wang
score:98.5
pay=1200 (這一項之前是沒有的)

看!這就是虛函數的奧妙感化。如今用統一個指針變量(指向基類對象的指針變量),不只輸入了先生stud1的全體數據,並且還輸入了研討生grad1的全體數據,解釋已挪用了grad1的display函數。用統一種挪用情勢“pt->display()”,並且pt是統一個基類指針,可以挪用統一類族中分歧類的虛函數。這就是多態性,對統一新聞,分歧對象有 分歧的呼應方法。

解釋:原來基類指針是用來指向基類對象的,假如用它指向派生類對象,則停止指針類型轉換,將派生類對象的指針先轉換為基類的指針,所以基類指針指向的是派生類對象中的基類部門。在法式修正前,是沒法經由過程基類指針去挪用派生類對象中的成員函數的。虛函數沖破了這一限制,在派生類的基類部門中,派生類的虛函數代替了基類本來的虛函數,是以在使基類指針指向派生類對象後,挪用虛函數時就挪用了派生類的虛函數。 要留意的是,只要用virtual聲清楚明了虛函數後才具有以上感化。假如不聲明為虛函數,妄圖經由過程基類指針挪用派生類的非虛函數是不可的。

虛函數的以上功效是很有適用意義的。在面向對象的法式設計中,常常會用到類的繼續,目標是保存基類的特征,以削減新類開辟的時光。然則,從基類繼續來的某些成員函數不完整順應派生類的須要,例如在例中,基類的display函數只輸入基類的數據,而派生類的display函數須要輸入派生類的數據。曩昔我們已經使派生類的輸入函數與基類的輸入函數分歧名(如display和display1),但假如派生的條理多,就要起很多分歧的函數名,很不便利。假如采取同名函數,又會產生同名籠罩。

應用虛函數就很好地處理了這個成績。可以看到:當把基類的某個成員函數聲明為虛函數後,許可在其派生類中對該函數從新界說,付與它新的功效,而且可以經由過程指向基類的指針指向統一類族中分歧類的對象,從而挪用個中的同名函數。由虛函數完成的靜態多態性就是:統一類族中分歧類的對象,對統一函數挪用作出分歧的呼應。

虛函數的應用辦法是:
在基類用virtual聲明成員函數為虛函數。
如許便可以在派生類中從新界說此函數,為它付與新的功效,並能便利地被挪用。在類外界說虛函數時,不用再加virtual。
在派生類中從新界說此函數,請求函數名、函數類型、函數參數個數和類型全體與基類的虛函數雷同,並依據派生類的須要從新界說函數體。
C++劃定,當一個成員函數被聲明為虛函數後,其派生類中的同名函數都主動成為虛函數。是以在派生類從新聲明該虛函數時,可以加virtual,也能夠不加,但習氣上普通在每層聲明該函數時都加virtual,使法式加倍清楚。假如在派生類中沒有對基類的虛函數從新界說,則派生類簡略地繼續其直接基類的虛函數。
界說一個指向基類對象的指針變量,並使它指向統一類族中須要挪用該函數的對象。
經由過程該指針變量挪用此虛函數,此時挪用的就是指針變量指向的對象的同名函數。
經由過程虛函數與指向基類對象的指針變量的合營應用,就可以便利地挪用統一類族中分歧類的同名函數,只需先用基類指針指向便可。假如指針赓續地指向統一類族中分歧類的對象,就可以赓續地挪用這些對象中的同名函數。這就好像後面說的,赓續地告知出租車司機要去的目標地,然後司機把你送到你要去的處所。

須要解釋;有時在基類中界說的非虛函數會在派生類中被從新界說(如例中的area函數),假如用基類指針挪用該成員函數,則體系會挪用對象中基類部門的成員函數;假如用派生類指針挪用該成員函數,則體系會挪用派生類對象中的成員函數,這其實不是多態性行動(應用的是分歧類型的指針),沒有效到虛函數的功效。

之前引見的函數重載處置的是統一條理上的同名函數成績,而虛函數處置的是分歧派生條理上的同名函數成績,前者是橫向重載,後者可以懂得為縱向重載。但與重載分歧的是:統一類族的虛函數的首部是雷同的,而函數重載時函數的首部是分歧的(參數個數或類型分歧)。

在甚麼情形下應該聲明虛函數
應用虛函數時,有兩點要留意:
只能用virtual聲明類的成員函數,使它成為虛函數,而不克不及將類外的通俗函數聲明為虛函數。由於虛函數的感化是許可在派生類中對基類的虛函數從新界說。明顯,它只能用於類的繼續條理構造中。
一個成員函數被聲明為虛函數後,在統一類族中的類就不克不及再界說一個非virtual的但與該虛函數具有雷同的參數(包含個數和類型)和函數前往值類型的同名函數。

依據甚麼斟酌能否把一個成員函數聲明為虛函數呢?重要斟酌以下幾點:
起首算作員函數地點的類能否會作為基類。然後算作員函數在類的繼續後有沒有能夠被更改功效,假如願望更改其功效的,普通應當將它聲明為虛函數。
假如成員函數在類被繼續後功效不需修正,或派生類用不到該函數,則不要把它聲明為虛函數。不要僅僅斟酌到要作為基類而把類中的一切成員函數都聲明為虛函數。
應斟酌對成員函數的挪用是經由過程對象名照樣經由過程基類指針或援用去拜訪,假如是經由過程基類指針或援用去拜訪的,則應該聲明為虛函數。
有時,在界說虛函數時,其實不界說其函數體,即函數體是空的。它的感化只是界說了一個虛函數名,詳細功效留給派生類去添加。

須要解釋的是:應用虛函數,體系要有必定的空間開支。當一個類帶有虛函數時,編譯體系會為該類結構一個虛函數表(virtual function table,簡稱vtable),它是一個指針數組,寄存每一個虛函數的進口地址。體系在停止靜態聯系關系時的時光開支是很少的,是以,多態性是高效的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved