不要在建構子中呼叫虛擬函式

最近發現當在建構子中設計要去呼叫虛擬函式時,會發生衍生類別因為還未完全執行完建構子的初始化動作,就直接呼叫它所改寫的虛擬函式的話,可能會引發一些問題。

例如:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VS2020Test
{
    public class CallVirtualFuncFromCtor
    {
        public static void UT()
        {
            MyDerivative md = new MyDerivative(2, 5);
        }
    }

    public class MyBase
    {
        protected int id = 0;
        public MyBase(int i)
        {
            id = i;

            ShowID();
        }

        public virtual void ShowID()
        {
            Console.WriteLine("[Base] ID " + id.ToString()); 
        }
    }

    public class MyDerivative : MyBase
    {
        protected int id2 = 0;

        public MyDerivative(int id, int id2)
            : base(id)
        {
            this.id2 = id2;
        }

        public override void ShowID()
        {
            Console.WriteLine("[Derivative] ID " + id.ToString() + ",ID2 " + id2.ToString() ); 
        }
    }
}

執行結果如下:

在C#的實作中,它會先執行衍生類別所改寫的虛擬函式。但因為這時候MyDerivative的建構子還未執行,所以id2中並沒有設定成使用者在建構MyDerivative物件時所指定的值。所以輸出的結果中,id2就是預設值0了。

C++的實作方式跟C#不同,它會是呼叫基底類別的虛擬函式

由於會有初始化未完全就執行其它相關函式的問題,所以在建構子中,最好是不要呼叫虛擬函式,或是說,最好是呼叫到只會使用到基底類別所提供的變數的虛擬函式。

留言

這個網誌中的熱門文章

DOS Batch指令檔中如何記錄log資訊

用捷徑方式執行需帶入命令列參數的Windows Form程式

使用regular expression來match中括號(square bracket)