施工期间的虚拟功能。为什么Java不同于C++

2022-09-04 02:12:52

我今天进行了一次测试,其中一个问题是关于在构造函数中使用虚拟方法C++。我失败了这个问题,我回答说不应该有任何问题,但是在阅读这篇文章后,我发现我错了。

因此,我理解不允许这样做的原因是因为派生对象未完全初始化,因此调用它的虚方法可能会导致无效后果。

我的问题是如何在Java / C#中解决的?我知道我可以在我的基构造函数中调用派生方法,我会假设这些语言有完全相同的问题。


答案 1

Java具有与C++非常不同的对象模型。在Java中,你不能有类类型的对象的变量 - 相反,你只能有对对象(类类型的)的引用。因此,类的所有成员(仅是引用)开始时都是微不足道的,直到整个派生对象在内存中设置完毕。只有这样,构造函数才会运行。因此,当基构造函数调用虚函数时,即使该函数被重写,被覆盖的函数至少可以正确地引用派生类的成员(这些成员本身可能尚未被赋值,但至少它们存在null

(如果它有帮助,你还可以考虑在Java中没有成员的每个类在技术上都是默认可构造的,至少在原则上是这样:与C++不同,Java没有常量或引用之类的东西(必须在C++中初始化),实际上根本没有初始值设定项列表。Java中的变量根本不需要初始化。它们要么是以 0 开头的基元,要么是以 . 开头的类类型引用。一个例外来自非静态类成员,它不能被反弹,实际上必须通过在每个构造函数中的某个地方有一个赋值语句来“初始化”[感谢@josefx指出这一点!]。finalnullfinal


答案 2

了解不允许这样做的原因是因为派生对象未完全初始化,因此调用它的虚方法可能会导致无效后果

错。C++将调用基类的方法实现,而不是派生类的实现。没有“无效后果”。避免构造的唯一有效原因是,该行为有时会令人惊讶。

这与 Java 不同,因为 Java 调用派生类的实现。


推荐