請將繼承來的虛擬函式都加上 override

如果想要成功覆寫 (override) 基底類別的虛擬函式 (virtual function),你應該知道要滿足一些條件:

  • 基底類別的函式要宣告為虛擬函式 (#1)。
  • 基底類別和衍生類別的函式名稱要相同 (#2)。
  • 基底類別和衍生類別的函式參數型別及個數要相同 (#3, #4)。
  • 基底類別和衍生類別的函式 const 或 volatile 宣告要相同 (#5, #6)。
  • 基底類別和衍生類別的函式回傳型態要相同 (#7)。
  • 基底類別和衍生類別的函式參考限定符要相同 (#8)。
  • 基底類別和衍生類別的函式例外規格要相同 (#9)。

假設有一個基底類別 (base class),如下:

class Base
{
public:
	virtual ~Base()
	{}
public:
	void NonVirtual() // #1
	{
		std::cout << "Base::NonVirtual" << std::endl;
	}
	virtual void DiffFuncName() // #2
	{
		std::cout << "Base::DiffFuncName" << std::endl;
	}
	virtual void DiffParamType(int n) // #3
	{
		std::cout << "Base::DiffParamType" << std::endl;
	}
	virtual void DiffParamNum(int n1, int n2) // #4
	{
		std::cout << "Base::DiffParamNum" << std::endl;
	}
	virtual void DiffConstState() const // #5
	{
		std::cout << "Base::DiffConstState" << std::endl;
	}
	virtual void DiffVolatileState() volatile // #6
	{
		std::cout << "Base::DiffVolatileState" << std::endl;
	}
	virtual double DiffReturnType() // #7
	{
		std::cout << "Base::DiffReturnType" << std::endl;
		return 0;
	}
	virtual void DiffRefType() & // #8
	{
		std::cout << "Base::DiffRefType" << std::endl;
	}
	virtual void DiffExceptionSpec() noexcept // #9
	{
		std::cout << "Base::DiffExceptionSpec" << std::endl;
	}
};

衍生類別 (derived class),如下:

class Derived : public Base
{
public:
	virtual ~Derived()
	{}
public:
	void NonVirtual() // #1
	{
		std::cout << "Derived::NonVirtual" << std::endl;
	}
	virtual void DiffFuncName1() // #2
	{
		std::cout << "Derived::DiffFuncName1" << std::endl;
	}
	virtual void DiffParamType(unsigned int n) // #3
	{
		std::cout << "Derived::DiffParamType" << std::endl;
	}
	virtual void DiffParamNum(int n1, int n2, int n3) // #4
	{
		std::cout << "Derived::DiffParamNum" << std::endl;
	}
	virtual void DiffConstState() // #5
	{
		std::cout << "Derived::DiffConstState" << std::endl;
	}
	virtual void DiffVolatileState() // #6
	{
		std::cout << "Derived::DiffVolatileState" << std::endl;
	}
	virtual float DiffReturnType() // #7
	{
		std::cout << "Derived::DiffReturnType" << std::endl;
		return 0;
	}
	virtual void DiffRefType() && // #8
	{
		std::cout << "Derived::DiffRefType" << std::endl;
	}
	virtual void DiffExceptionSpec() // #9
	{
		std::cout << "Derived::DiffExceptionSpec" << std::endl;
	}
};

以上這九種 case 都不能成功被 override,在筆者使用的 vs2019 也只報錯函式回傳型態不同 (#7) 及函式例外規格不同 (#9) 這兩種 case。

P.S. 如果 noexcept 是宣告在衍生類別,而基底類別沒有宣告,則因為是從寬鬆的例外規格變成嚴格的例外規格,可以成功覆寫。



可以看到拿掉無法編譯的 #7 及 #9,程式執行後全部都呼叫到基底類別的函式。



但如果衍生類別繼承來的虛擬函式都加上 override,則編譯器都會報錯。

class Derived : public Base
{
public:
	void NonVirtual() override; // #1
	virtual void DiffFuncName1() override;  // #2
	virtual void DiffParamType(unsigned int n) override; // #3
	virtual void DiffParamNum(int n1, int n2, int n3) override; // #4
	virtual void DiffConstState() override; // #5
	virtual void DiffVolatileState() override; // #6
	virtual float DiffReturnType() override; // #7
	virtual void DiffRefType() && override; // #8
	virtual void DiffExceptionSpec() override; // #9
};


從這裡就可以看出使用 override 關鍵字的好處了吧。



留言