1. 程式人生 > 程式設計 >C++ Virtual關鍵字的具體使用

C++ Virtual關鍵字的具體使用

基礎理解和demo

普通的繼承

#include<iostream>

class Parent {
public:
  void print() {
    std::cout << "Parent" << std::endl;
  }
};

class Child : Parent {
public:
  void print() {
    std::cout << "Child" << std::endl;
  }
};

int main() {
  Child c;
  c.print();
  return 0;
}

輸出結果為 "Child"

但是如果是 "父類的指標指向子類的物件" 這種情況下,使用這個父類的指標去呼叫被重寫的方法呢,結果會是什麼呢? 從語法的本質上講,子類物件的記憶體前半部分就是父類,因為可以將子類物件的指標直接轉化為父類。

#include<iostream>

class Parent {
public:
  void print() {
    std::cout << "Parent" << std::endl;
  }
};

// 注意這裡必須是 public Parent
// 不然會報錯 cannot cast 'Child' to its private base class 'Parent'
class Child : public Parent {
public:
  void print() {
    std::cout << "Child" << std::endl;
  }
};

int main() {
  Parent* p = new Child();
  p->print();
  return 0;
}

這個時候輸出的是 "Parent"

所以,當一個成員函式需要被子類重寫,那麼必須將其宣告為virtual,也就是 虛擬函式,注意,子類覆寫的方法的virtual關鍵字會自動繼承而來,可以顯示地寫或者不寫(建議還是寫上)。

這樣修改完就沒問題了:

#include<iostream>

class Parent {
public:
  virtual void print() {
    std::cout << "Parent" << std::endl;
  }
};

class Child : public Parent {
public:
  virtual void print() {
    std::cout << "Child" << std::endl;
  }
};

int main() {
  Parent* p = new Child();
  p->print();
  return 0;
}

加深理解

Virtual 關鍵字的一個重要概念 "只有在通過基類指標或引用間接指向派生類子型別時多型性才會起作用",也就是說,基類的函式呼叫如果有virtual則根據多型性呼叫派生類的,如果沒有virtual則是正常的靜態函式呼叫,還是呼叫基類的。

舉個例子

#include <iostream.h>
class Base
{
public:
virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
void g(float x){ cout << "Base::g(float) " << x << endl; }
void h(float x){ cout << "Base::h(float) " << x << endl; }
};
 
class Derived : public Base
{
public:
virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
void g(int x){ cout << "Derived::g(int) " << x << endl; }
void h(float x){ cout << "Derived::h(float) " << x << endl; }
};
 
void main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); // Derived::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14
// Bad : behavior depends on type of the pointer
pb->g(3.14f); // Base::g(float) 3.14
pd->g(3.14f); // Derived::g(int) 3 (surprise!)
// Bad : behavior depends on type of the pointer
pb->h(3.14f); // Base::h(float) 3.14 (surprise!)
pd->h(3.14f); // Derived::h(float) 3.14
}

貼上這個部落格的一段話,表達的就是這個意思:

bp 和dp 指向同一地址,按理說執行結果應該是相同的,而事實上執行結果不同,所以他把原因歸結為C++的隱藏規則,其實這一觀點是錯的。決定bp和dp呼叫函式執行結果的不是他們指向的地址,而是他們的指標型別。 “只有在通過基類指標或引用間接指向派生類子型別時多型性才會起作用”(C++ Primer 3rd Edition)。pb是基類指標,pd是派生類指標,pd的所有函式呼叫都只是呼叫自己的函式,和多型性無關,所以pd的所有函式呼叫的結果都輸出Derived::是完全正常的;pb的函式呼叫如果有virtual則根據多型性呼叫派生類的,如果沒有virtual則是正常的靜態函式呼叫,還是呼叫基類的,所以有virtual的f函式呼叫輸出Derived::,其它兩個沒有virtual則還是輸出Base::很正常啊 ,nothing surprise! 所以並沒有所謂的隱藏規則,雖然《高質量C++/C 程式設計指南》是本很不錯的書,可大家不要迷信哦。記住“只有在通過基類指標或引用間接指向派生類子型別時多型性才會起作用”。

到此這篇關於C++ Virtual關鍵字的具體使用的文章就介紹到這了,更多相關C++ Virtual關鍵字內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!