Yon*_*ona 32 c# c++ java constructor
我知道,从基类的构造函数调用虚方法可能是危险的,因为子类可能不处于有效状态.(至少在C#中)
我的问题是如果虚拟方法是初始化对象状态的那个?它是很好的做法,还是应该是两个步骤,首先创建对象,然后加载状态?
第一个选项:(使用构造函数初始化状态)
public class BaseObject {
public BaseObject(XElement definition) {
this.LoadState(definition);
}
protected abstract LoadState(XElement definition);
}
Run Code Online (Sandbox Code Playgroud)
第二种选择:(使用两步法)
public class BaseObject {
public void LoadState(XElement definition) {
this.LoadStateCore(definition);
}
protected abstract LoadStateCore(XElement definition);
}
Run Code Online (Sandbox Code Playgroud)
在第一种方法中,代码的使用者可以使用一个语句创建和初始化对象:
// The base class will call the virtual method to load the state.
ChildObject o = new ChildObject(definition)
Run Code Online (Sandbox Code Playgroud)
在第二种方法中,消费者必须创建对象然后加载状态:
ChildObject o = new ChildObject();
o.LoadState(definition);
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 39
(这个答案适用于C#和Java.我相信C++在这个问题上的工作方式不同.)
在构造函数中调用虚方法确实很危险,但有时它最终会得到最干净的代码.
我会尽量避免在可能的情况,但没有弯曲的设计巨大.(例如,"后来初始化"选项禁止不变性.)如果你做在构造函数中使用虚拟方法,将其记录下来非常强烈.只要所涉及的每个人都知道它在做什么,就不应该造成太多问题.我会尝试限制可见性,就像你在第一个例子中所做的那样.
编辑:这里重要的一件事是C#和Java之间的初始化顺序有所不同.如果你有一个类,如:
public class Child : Parent
{
private int foo = 10;
protected override void ShowFoo()
{
Console.WriteLine(foo);
}
}
Run Code Online (Sandbox Code Playgroud)
其中Parent构造函数调用ShowFoo,在C#,将显示10 Java中的等效方案将显示0.
Gre*_*ers 10
在C++中,在基类构造函数中调用虚方法只会调用该方法,就好像派生类还不存在一样(因为它没有).这意味着调用在编译时被解析为它应该在基类(或它派生自的类)中调用的任何方法.
通过GCC测试,它允许您从构造函数调用纯虚函数,但它会发出警告,并导致链接时错误.标准似乎未定义此行为:
"可以从抽象类的构造函数(或析构函数)调用成员函数; 直接或间接地对从这样的创建(或销毁)的对象进行虚拟调用(class.virtual)到纯虚函数的效果构造函数(或析构函数)未定义."