在 C++ 中免不了學到物件導向,其中 virtual function 是其中一個小概念。
虛擬函式 Virtual Function
首先要理解 Base
是父類,被 Derived
子類繼承 Base
。
當我們宣告 virtual function 後,若有繼承的 class 的話,這個函式可以被重新定義。像是下方 func1()
和 func2()
都可以覆寫,若沒有覆寫的話就是以父類為主。(不強制子類實作)
class Base {
public:
virtual void func1() {}
virtual void func2() {}
void nonVirtualfunc() {}
};
class Derived : public Base {
public:
virtual void func2() override {}
void nonVirtualfunc() {}
};
Base testBase;
Derived testDerived;
實際例子可看下方:
# include <iostream> # include <vector> using namespace std; class Animal { public: virtual void intro() { cout << "Animal: I am Animal." << endl; } virtual ~Animal() {} }; class Wolf : public Animal { public: virtual void intro() override { cout << "Wolf: I am Wolf." << endl; } }; class Dog : public Animal { public: virtual void intro() override { cout << "Dog: I am Dog." << endl; } }; class OtherAnimal : public Animal {}; int main() { vector<Animal*> animals; animals.push_back(new Animal()); animals.push_back(new Wolf()); animals.push_back(new Dog()); animals.push_back( new OtherAnimal() ); for(vector<Animal*>::const_iterator it = animals.begin(); it != animals.end(); it++) { (*it)->intro(); delete *it; } return 0; }
Ouput
Animal: I am Animal.
Wolf: I am Wolf.
Dog: I am Dog.
Animal: I am Animal.
而如果將virtual void intro() { cout << "Animal: I am Animal." << endl; }
改為void intro() const { cout << "Animal: I am Animal." << endl; }
output 就會變成:
Animal: I am Animal.
Animal: I am Animal.
Animal: I am Animal.
Animal: I am Animal.
如果以網頁設計來講,有點像是預設版型和指定版型。如果網頁頁面沒有指定版型,那排版就會是預設的,像是 Animal
,如果有指定,那就照指定的去覆蓋。但若是沒有開放客製,像是沒有宣告為虛擬函式的話,那就全部都是預設。
純虛函式 Pure Virtual Function
直接看以下例子,寫法就類似 virtual void func1() = 0
,並沒有實作。也就是說 Base
它是抽象類別,不能被實體化,這樣表示子類一定要實作。
class Base {
public:
virtual void func1() = 0;
};
class Derived : public Base {
public:
virtual void func1() override {
cout << "Derived func1\n";
}
};
像是下方程式碼,OtherAnimal
沒有實作,結果噴出錯誤:error: cannot declare variable ‘otherAnimal_a’ to be of abstract type ‘OtherAnimal’
#include <iostream> using namespace std; class Animal { public: virtual void intro() = 0; }; class Dog : public Animal { public: virtual void intro() override { cout << "Dog: I am Dog." << endl; } }; class OtherAnimal : public Animal {}; int main() { Dog dog_a; dog_a.intro(); OtherAnimal otherAnimal_a; otherAnimal_a.intro(); return 0; }
以網頁的概念來講,有點像是強制每次製作一個頁面一定要選一個版型,沒有預設的版型可套用,所以如果沒有選擇的話,就會噴錯。
那麼我把 OtherAnimal
那段刪掉,改成如下寫法:
#include <iostream> using namespace std; class Animal { public: virtual void intro() = 0; }; class Wolf : public Animal { public: virtual void intro() override { cout << "Wolf: I am Wolf." << endl; } }; class Dog : public Animal { public: virtual void intro() override { cout << "Dog: I am Dog." << endl; } }; int main() { Dog dog_a; dog_a.intro(); Wolf wolf_a; wolf_a.intro(); Animal *animal_a = new Dog(); animal_a->intro(); return 0; }
Output
Dog: I am Dog.
Wolf: I am Wolf.
Dog: I am Dog.
這裡就先簡單紀錄一下,之後若有更深層的理解會再更新或是新增篇章。