0

我想要一个在基类中定义的字段,它将影响属于基类的对象的创建。但是,我希望能够在调用基类 cto'r之前覆盖该字段的值。一个例子:

class ObjNeedParam
{
    public ObjNeedParam(int p)
    {
        val = p;
    }
    int val;
    int Value{get{return Value;}}
}
class Base
{
    public Base()
    {
        obj = new ObjNeedParam(paramVal);
    }
    ObjNeedParam obj;
    protected int paramVal = 1;
}

class Derived : Base
{
    public Derived()
    { 
        //Once I'm here, obj has already been created with paramVal=1 instead of 2!            
        dummy = 3;
    }
    new int paramVal = 2;
    int dummy;
}
4

2 回答 2

3

这种做法有些可疑,因此您可能想在这里重新考虑您的方法。

如果您仍想继续执行此操作,正确的方法是使用一个virtual方法将此值提供给基本构造函数:

class Base
{
    public Base()
    {
        obj = new ObjNeedParam(GetParamVal());
    }

    protected virtual int GetParamVal() { return 1; }
}

class Derived : Base
{
    protected override int GetParamVal() { return 2; }
}

您必须确保override不使用在的构造Derived函数中初始化的Derived任何类成员,因为该构造函数在调用覆盖时尚未运行!请参阅构造函数中的虚拟成员调用

更新:这有点值得怀疑,因为在构造某个派生类型的对象时,编译器有一个问题要解决:字段应该以什么顺序初始化,构造函数运行,以便保证任何构造函数内部的任何方法调用都能找到对象处于“可用”状态?

这个问题在一般情况下无法解决,因为根据定义,直到所有构造函数都返回,对象才处于可用状态,我们正在谈论从这些构造函数内部调用方法。因此,编译器必须尽可能多地保证,并防止或允许您做无法证明安全的事情。

在这种情况下,C++(有趣地)阻止了无法证明安全的事情,而 C# 允许这样做。因此,这有点值得怀疑,因为如果您不注意,可能会引入错误。更安全的方法是编写类,以便在构造函数运行后初始化该成员。

于 2012-07-18T09:35:38.743 回答
1

您需要做的不是以这种方式初始化该字段。一种替代方法是将字段设为属性,并允许由子类覆盖。或者,允许通过参数在基类构造函数中设置字段,因此您可以编写如下代码:

class Base
{
    public Base() : this(1)
    {
    }

    public Base(int param)
    {
        paramVal = param;
    }

    private int paramVal;
}

class Derived : Base
{
    public Derived() : base(2)
    {   
    }
}

最终,一个字段通常是类私有的,并且永远不会被派生类覆盖。如果您想公开它以供派生类操作,那么您可能需要字段以外的东西。

于 2012-07-18T09:40:21.700 回答