避免在构造函数中调用虚方法(Do not call overridable methods in constructors)

Posted 蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了避免在构造函数中调用虚方法(Do not call overridable methods in constructors)相关的知识,希望对你有一定的参考价值。

CLR中说道,不要在构造函数中调用虚方法,原因是假如被实例化的类型重写了虚方法,就会执行派生类型对虚方法的实现。但在这个时候,尚未完成对继承层次结构中所有字段的初始化。所以,调用虚方法会导致不可预测的行为。归根结底,这是由于调虚方法时,直到运行时之前,都不会选择执行该方法的实际类型。

在MSDN中,也给我我们详细的提示和范例。

https://msdn.microsoft.com/en-us/library/ms182331.aspx

那我们就亲手来测试一下,新建两个类,Perople类,Chinese类,先不要看结果,看到下面这两个类,想想在实例化Chinese的时候,会是什么输出结果呢?

 1  public class People
 2     {
 3         public People()
 4         {
 5             PeopleSayHello();
 6         }
 7 
 8         public virtual void PeopleSayHello()
 9         {
10             Console.WriteLine("hello");
11         }
12     }
public class Chinese : People
    {
        private bool HaveAbility { get; set; }

        public Chinese()
        {
            HaveAbility = true;
        }

        public override void PeopleSayHello()
        {
            
            Console.WriteLine((HaveAbility?"":"没有")+"能力说你好");
        }
    }

接下来来看调用和输出结果吧:

是不是和你在脑海里运行的结果相同?

其实原因在第一句话中已经说的比较清晰了,更通俗的说就是在派生类实例化的时候,如果没有显式调用基的任意一个构造函数,那么默认选择基类的无参构造。所以在本例中,实例化Chinese的时候,首先执行了基类的无参构造。

和实例构造器初始化的顺序也相关,在创建实例的时候,首先为数据字段分配内存,然后初始化对象附加字段,包括类型对象的指针引用,最后才调用类型的构造函数设置对象的初始状态。

 

以上是关于避免在构造函数中调用虚方法(Do not call overridable methods in constructors)的主要内容,如果未能解决你的问题,请参考以下文章

C++在构造函数中调用最终的虚函数

为何需要虚函数 直接对象名加作用域来调用子类父类爷类的函数不就行了 为啥

lapply和do.call有什么区别?

面向对象:继承抽象类抽象方法虚方法

static函数如何调用虚函数

绝不在构造函数和析构函数中调用虚函数