调用派生类的构造函数在基类的构造函数之前执行

Posted

技术标签:

【中文标题】调用派生类的构造函数在基类的构造函数之前执行【英文标题】:Invoking constructor of derived class execute before constructor of base class 【发布时间】:2013-05-11 15:46:43 【问题描述】:

嗯,最初我在每个派生类中有几个具有不同值的常量(如 MAX_SPEED)。这个想法是在基类的某些方法中使用这些值。那时我意识到我不能用常量做到这一点,所以我创建了只读属性。

我需要一种在实例化时将这些值分配给私有字段的方法,最好是在基类中。但首先我必须评估派生类中的原始值。由于这些是属性,我在定义时找不到初始化它们的方法,所以唯一的方法是在派生构造函数中。

这就是问题所在:值在分配给基类中的私有字段后被初始化。我逃脱的解决方案是创建一个虚拟方法并在那里进行分配。

有没有办法从派生类调用基构造函数,以便首先调用来自派生构造函数的代码?

class BaseClass

    public BaseClass()
    
        System.Console.WriteLine("This should be shown after");
    


class DerivedClass : BaseClass

    public DerivedClass() : base()
    
        System.Console.WriteLine("This should be shown first");
    

当然,在示例中它会以相反的方式工作。有解决办法吗?

【问题讨论】:

没有。您必须先调用基本构造函数,否则会出现错误。顺便说一句,你为什么要这个? 我在对 Jon 的回答的评论中描述了这种情况。我想我应该在问题中说清楚。 【参考方案1】:

没有。基类构造函数总是在派生类构造函数的主体之前执行。然而:

派生类中的任何实例变量初始值设定项都在基类构造函数之前执行 基类构造函数可以执行可以在派生类中重写的虚方法。 虽然这几乎总是一个坏主意。(此时所有类型的正常前置条件都无效。您可以观察尚未设置的只读变量,因为它们将在构造函数主体中设置,例如。Ick。)

为了证明这两个:

using System;

class BaseClass

    public BaseClass()
    
        VirtualMethod();
        Console.WriteLine("BaseClass ctor body");
    

    public virtual void VirtualMethod()
    
        Console.WriteLine("BaseClass.VirtualMethod");
    


class DerivedClass : BaseClass

    int ignored = ExecuteSomeCode();

    public DerivedClass() : base()
    
        Console.WriteLine("DerivedClass ctor body");
    

    static int ExecuteSomeCode()
    
        Console.WriteLine("Method called from initializer");
        return 5;
    

    public override void VirtualMethod()
    
        Console.WriteLine("DerivedClass.VirtualMethod");
    


class Test

    static void Main()
    
        new DerivedClass();
    

输出:

Method called from initializer
DerivedClass.VirtualMethod
BaseClass ctor body
DerivedClass ctor body

另外,如果你的基类构造函数有一个参数,那么你可以在派生类中执行一些代码来提供一个参数:

DerivedClass() : base(SomeStaticMethod())

不过,所有这些都相当臭。你的具体情况是什么?

【讨论】:

嗯,最初我在每个派生类中有几个具有不同值的常量(如 MAX_SPEED)。这个想法是在基类的某些方法中使用这些值。那时我意识到我不能用常量做到这一点,所以我创建了只读属性。 我需要一种方法在实例化时将这些值分配给私有字段,最好是在基类中。但首先我必须评估派生类中的原始值。由于这些是属性,我在定义时找不到初始化它们的方法,所以唯一的方法是在派生构造函数中。 这就是问题所在:值在分配给基类中的私有字段后被初始化。我逃脱的解决方案是(正如你提到的)创建一个虚拟方法并在那里进行分配。 @msgmaxim: 你能在派生类中用静态方法计算最大值,然后将它作为参数传递给基类吗?我强烈建议反对 使用构造函数中的虚拟方法,除非真的有没有 其他方式。它最终会变得非常复杂。 我想这也可能是解决方案。【参考方案2】:

不,你不能那样做。基类总是首先初始化。但是,您可以执行以下操作:

class BaseClass

    public BaseClass()
    
        this.Initialize();
    

    protected virtual void Initialize()
    
        System.Console.WriteLine("This should be shown after");
    


class DerivedClass : BaseClass

    public DerivedClass() : base()
    
    

    protected override void Initialize()
    
        System.Console.WriteLine("This should be shown first");
        base.Initialize();
    

【讨论】:

这正是我在构造函数失败后在实际程序中所做的!还是谢谢你!【参考方案3】:

另一种选择是将子类构造函数设置为 static ,以便它比父类构造函数先执行。但它违反了 oop 设计并不可取

【讨论】:

以上是关于调用派生类的构造函数在基类的构造函数之前执行的主要内容,如果未能解决你的问题,请参考以下文章

派生类(构造函数)中基类的成员变量初始化顺序

C++中派生类的构造函数怎么显式调用基类构造函数?

为啥执行时没有执行基类的构造函数?

派生类的构造函数

生成一个派生类对象时,调用基类和派生类构造函数按啥次序

派生类的构造函数与析构函数的调用顺序