攝影師:Caio: https://www.pexels.com/zh-tw/photo/46274/

[基礎概念] 虛擬函式 Virtual Function 是什麼東西?

在 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.

這裡就先簡單紀錄一下,之後若有更深層的理解會再更新或是新增篇章。

讓我知道你在想什麼!