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"
但是如果是 "父類的指針指向子類的對象" 這種情況下, 使用這個父類的指針去調(diào)用被重寫的方法呢, 結果會是什么呢? 從語法的本質(zhì)上講, 子類對象的內(nèi)存前半部分就是父類, 因為可以將子類對象的指針直接轉化為父類。
#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" 。
所以, 當一個成員函數(shù)需要被子類重寫, 那么必須將其聲明為virtual, 也就是 虛函數(shù) , 注意, 子類覆寫的方法的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 關鍵字的一個重要概念 "只有在通過基類指針或引用間接指向派生類子類型時多態(tài)性才會起作用" , 也就是說, 基類的函數(shù)調(diào)用如果有virtual則根據(jù)多態(tài)性調(diào)用派生類的,如果沒有virtual則是正常的靜態(tài)函數(shù)調(diào)用,還是調(diào)用基類的。
舉個例子
#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++的隱藏規(guī)則,其實這一觀點是錯的。決定bp和dp調(diào)用函數(shù)運行結果的不是他們指向的地址,而是他們的指針類型。 “只有在通過基類指針或引用間接指向派生類子類型時多態(tài)性才會起作用”(C++ Primer 3rd Edition)。pb是基類指針,pd是派生類指針,pd的所有函數(shù)調(diào)用都只是調(diào)用自己的函數(shù),和多態(tài)性無關,所以pd的所有函數(shù)調(diào)用的結果都輸出Derived::是完全正常的;pb的函數(shù)調(diào)用如果有virtual則根據(jù)多態(tài)性調(diào)用派生類的,如果沒有virtual則是正常的靜態(tài)函數(shù)調(diào)用,還是調(diào)用基類的,所以有virtual的f函數(shù)調(diào)用輸出Derived::,其它兩個沒有virtual則還是輸出Base::很正常啊 ,nothing surprise! 所以并沒有所謂的隱藏規(guī)則,雖然《高質(zhì)量C++/C 編程指南》是本很不錯的書,可大家不要迷信哦。記住“只有在通過基類指針或引用間接指向派生類子類型時多態(tài)性才會起作用”。
到此這篇關于C++ Virtual關鍵字的具體使用的文章就介紹到這了,更多相關C++ Virtual關鍵字內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C語言數(shù)據(jù)結構之二叉樹的非遞歸后序遍歷算法
這篇文章主要介紹了C語言數(shù)據(jù)結構之二叉樹的非遞歸后序遍歷算法的相關資料,希望通過本文能幫助到大家,讓大家實現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10
Visual Studio 2022 的安裝和創(chuàng)建C++項目(圖文教程)
本文主要介紹了Visual Studio 2022 的安裝和創(chuàng)建C++項目,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-05-05
基于C++實現(xiàn)BMI身體質(zhì)量指數(shù)計算工具
BMI(Body?Mass?Index,身體質(zhì)量指數(shù)),也稱為體重指數(shù),是一種常用的衡量成人人體肥胖程度的指標,本文就來用C++編寫一個簡單的BMI計算工具吧2023-10-10
C++靜態(tài)庫與動態(tài)庫文件的生成和使用教程
庫文件是計算機上的一類文件,可以簡單的把庫文件看成一種代碼倉庫,它提供給使用者一些可以直接拿來用的變量、函數(shù)和類,下面這篇文章主要給大家介紹了關于C++靜態(tài)庫與動態(tài)庫文件的生成和使用的相關資料,需要的朋友可以參考下2023-03-03

