我认为根据 OOP 的设计,虚拟化在超类构造函数中不起作用。例如,请考虑以下 C# 代码。
using System;
namespace Problem
{
public class BaseClass
{
public BaseClass()
{
Console.WriteLine("Hello, World!");
this.PrintRandom();
}
public virtual void PrintRandom()
{
Console.WriteLine("0");
}
}
public class Descendent : BaseClass
{
private Random randomValue;
public Descendent()
{
Console.WriteLine("Bonjour, Monde!");
randomValue = new Random();
}
public override void PrintRandom()
{
Console.WriteLine(randomValue.NextDouble().ToString());
}
public static void Main()
{
Descendent obj = new Descendent();
obj.PrintRandom();
Console.ReadLine();
}
}
}
此代码会中断,因为当创建 Descendent 对象时,它会调用基类构造函数,并且我们在基类构造函数中调用了一个虚方法,该虚方法调用又调用了派生类的方法,因此它崩溃了,因为那时 randomValue 尚未初始化。
类似的代码在 C++ 中工作,因为对 PrintRandom 的调用不会路由到派生类,因为 IMO,C++ 中的顺序类似于:
1. 调用基类构造函数
2. 更新 V - 此类的表
3.调用构造函数代码
我的问题是,首先我是否正确,根据 OOP 原则,虚拟化不应该/不能在超类构造函数中工作,其次如果我是对的,那么为什么所有 .NET 语言的行为都不同(我有使用 C#、VB.NET 和 MC++ 进行了测试)
在本机 C++ 中,程序按预期工作:您可以在基类构造函数中调用基类版本的虚函数。在构造函数调用时,仅存在基类及其虚函数,因此您获得当时定义的虚函数的最低级别版本。这并不意味着不能使用虚拟化,只是您不会在基类的构造函数中获得虚拟方法的子类版本(这就是不推荐的原因)。
显然,正如您所看到的,托管代码的工作方式不同,因为 (iirc) 整个对象是在调用构造函数之前构建的,因此您在子类构造函数之前获得子类虚函数。这是语言行为之间的记录差异,但在 .NET 语言之间应该保持一致(因为它们都编译为相同的 IL)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)