C++虛函數【Java有虛函數嗎?】

 

1,簡單介紹

  定義在基類中的函數,子類必須對其進行覆寫!必須對其進行覆寫?!】——Java中的接口、Abstract方法中的抽象類也有這樣的要求ios

  C++中定義:編程

virtual void deal();//子類必需要對這個函數進行覆寫

 

2,主要做用

  (1)定義子類對象,並調用對象中未被子類覆蓋的基類函數A。同時在該函數A中,又調用了已被子類覆蓋的基類函數B。那此時將會調用基類中的函數B,可咱們本應該調用的是子類中的覆蓋函數B。虛函數即能解決這個問題。ide

  ①沒有使用虛函數的例子:函數

#include<iostream>
using namespace std;
class Father                    //基類 Father
{
public:
    void display() {cout<<"Father::display()\n";}
    //在函數中調用了,子類覆蓋基類的函數display() 
    void fatherShowDisplay() {display();} 
};

class Son:public Father                 //子類Son 
{
public:
    //重寫基類中的display()函數
    void display() {cout<<"Son::display()\n";}
};

int main()
{
    Son son;        //子類對象 
    son.fatherShowDisplay();    //經過基類中未被覆蓋的函數,想調用子類中覆蓋的display函數 
}

  輸出結果爲:Father::display()  spa

  指望出現的結果應該爲:Son::display.net

  問題出現啦:指針

  子類Son繼承父類Father,而且覆寫了父類中的dispaly方法,講道理咱們後續調用子類中的dispaly方法應該想要使用咱們覆寫的方法;code

  可是因爲咱們調用的父類中未被覆寫的fatherShowDisplay方法調用了父類的display方法,因此致使程序調用的時候調用了父類的display方法!xml

  通俗說法咱們國家數據局早已經更新【覆寫】了國民經濟指數,可是你局裏員工【內部其餘方法】給外人調數據的時候仍是調用的之前的老舊數據!!!這樣不太合適吧!對象

 

  ②使用虛函數的狀況,再來看看輸出結果

#include<iostream>
using namespace std;
class Father                    //基類 Father
{
public:
    virtual void display() {cout<<"Father::display()\n";}
    //在函數中調用了,子類覆蓋基類的函數display() 
    void fatherShowDisplay() {display();} 
};

class Son:public Father                 //子類Son 
{
public:
    //重寫基類中的display()函數
    void display() {cout<<"Son::display()\n";}
};

int main()
{
    Son son;        //子類對象 
    son.fatherShowDisplay();    //經過基類中未被覆蓋的函數,想調用子類中覆蓋的display函數 
}

  輸出結果爲:Son::display()

  輸出結果是咱們指望的結果。

  ③先不查資料,本身在Java中實現上面①中的函數看看輸出結果

class Father{
    public void display(){
        System.out.println("父類顯示000000000");
    }
    public void fatherShowDisplay(){
        display();
    }
}

class Son extends Father{
    @Override/
    public void display() {
        System.out.println("子類顯示111111111");
    }
}



public class Client {
    public static void main(String[] args) {
        Father father=new Father();
        Son son=new Son();

        father.fatherShowDisplay();
        son.fatherShowDisplay();
    }
}

  顯示結果【Java沒有出現C++中遇到的相關問題!】:

父類顯示000000000
子類顯示111111111

 

  (2)在使用指向子類對象基類指針,並調用子類中的覆蓋函數時,若是該函數不是虛函數,那麼將調用基類中的該函數;若是該函數是虛函數,則會調用子類中的該函數。

  ①有使用虛函數的例子

#include<iostream>
using namespace std;
class Father                    //基類 Father
{
public:
    void display()
    {cout<<"Father::display()\n";}
};

class Son:public Father                 //子類Son 
{
public:
    void display()          //覆蓋基類中的display函數 
    {cout<<"Son::display()\n";}
};

int main()
{
    Father *fp;     //定義基類指針 
    Son son;        //子類對象 
    fp=&son;        //使基類指針指向子類對象 
    fp->display();  //經過基類指針想調用子類中覆蓋的display函數 
}

  輸出結果:Father::display()

  果真是調用了父類中的原始方法,沒有調用子類覆寫的方法

  ②使用虛函數的例子

#include<iostream>
using namespace std;
class Father                    //基類 Father
{
public:
    void virtual display()  //定義了虛函數
    {cout<<"Father::display()\n";}
};

class Son:public Father //子類Son 
{
public:
    void display()          //覆蓋基類中的display函數 
    {cout<<"Son::display()\n";}
};

int main()
{
    Father *fp;     //定義基類指針 
    Son son;        //子類對象 
    fp=&son;        //使基類指針指向子類對象 
    fp->display();  //經過基類指針想調用子類中覆蓋的display函數 
}

  使用虛函數的輸出結果:Son::display()

  確實調用的子類覆寫方法

  通俗說法②:如今一名將軍【本質上也是士兵】-用手指指着【指針】-士兵【實例化對象】詢問名字【調用方法】,一對父子也在軍隊中服役,當詢問老父親【父類對象】的名字的時候,父親向將軍報上本身的名字;當詢問兒子【子類對象】的名字時,他居然報了他爹的名字!!!

  ③Java中的例子【Java對象引用-C++指針】

class Father{
    public void display(){
        System.out.println("父類顯示000000000");
    }
    public void fatherShowDisplay(){
        display();
    }
}

class Son extends Father {
    @Override
    public void display() {
        System.out.println("子類顯示111111111");
    }
}

public class Client {
    public static void main(String[] args) {
//        Father son=new Son();//這種和下面的實際上是同樣的,【對象向上轉型】

        Father father=new Father();
        father.fatherShowDisplay();

        father=new Son();
        father.fatherShowDisplay();
        
    }
}

程序輸出:

父類顯示000000000
子類顯示111111111

  這種狀況下,Java依然沒有C++虛函數那樣的問題!!!

三、實際意義

  經過2-主要做用,他解決的問題知道:虛函數是爲了解決子類覆寫方法的一致性,一旦覆寫後續調用所有都使用最新的方法,不出現調用之前方法的狀況!對比一下Java語言中的方法覆寫!

 虛函數就是爲了解決編程中的多態特性嗎!

4,實現原理

   動態連編,在運行的時候肯定該調用哪一個函數。
  因爲子類中存在覆蓋函數,至關於該子類對象中有 兩個函數。那麼動態連編也能夠解釋爲,是在定義對象調用 構造函數時,將該虛函數與該類 綁定在一塊兒。
  基類指針指向基類對象,那調用的確定是基類虛函數;指向子類對象,那就調用子類虛函數。 由於在定義基類或子類對象時,就將虛函數與該類綁定
  小知識:
    編譯程序在編譯階段並不能確切知道將要調用的函數,只有在程序運行時才能肯定將要調用的函數,爲此要確切知道該調用的函數,要求聯編工做要在程序運行時進行,這種在程序運行時進行聯編工做被稱爲動態聯編。
  動態聯編必須包括如下方面:
    (1)成員函數必須聲明爲virtual
    (2)若是基類中聲明瞭爲虛函數,則派生類中沒必要再聲明。
  調用方式:
    經過對象的指針或引用調用成員函數;或經過成員函數調用,反之就沒法實現動態聯編。

5,Java中是否存在虛函數???

   首先聲明,Java中沒有虛函數這個概念、也不存在C++虛函數這樣的問題,緣由:Java自己【面向對象都有】的三大特性中就有多態這個特性。

  Java的普通函數就至關於C++的虛函數,動態綁定是Java的默認行爲【核心:Java沒有虛函數的本質緣由所在】。

6,Java實現C++遇到的問題

  代碼以下:

class Father{
    private void display(){//私有化該方法,子類就不能覆寫該方法
        System.out.println("父類顯示000000000");
    }
    public void fatherShowDisplay(){
        display();
    }
}

class Son extends Father{
    public void display() {//這裏不是覆寫父類方法,而是建立了一個全新的方法
        System.out.println("子類顯示111111111");
    }
}

public class Client {
    public static void main(String[] args) {
        Father father=new Father();
        Son son=new Son();
        Father fs=new Son();//向上轉型

        father.fatherShowDisplay();
        son.fatherShowDisplay();
        son.display();

        fs.fatherShowDisplay();
        ((Son)fs).display();//【強制】向下轉型
    }
}

  數據輸出:

父類顯示000000000
父類顯示000000000
子類顯示111111111
父類顯示000000000
子類顯示111111111

  這裏的方法已經不是覆寫了,而是父類的方法被私有化,子類是至關於新建了一個方法。

 

7,參考連接

https://www.jianshu.com/p/d07e0ac0ba3c?from=singlemessage

 https://blog.csdn.net/trojanpizza/article/details/6556604

相關文章
相關標籤/搜索