C# 从父类调用重写的方法
我尝试从父类的构造函数中调用重写的方法,并注意到不同语言的不同行为C# 从父类调用重写的方法,c#,java,c++,inheritance,polymorphism,C#,Java,C++,Inheritance,Polymorphism,我尝试从父类的构造函数中调用重写的方法,并注意到不同语言的不同行为 C++-回显A.foo() class A{ public: A(){foo();} virtual void foo(){cout<<"A.foo()";} }; class B : public A{ public: B(){} void foo(){cout<<"B.foo()";} }; int main(){ B *b = new B(
C++
-回显A.foo()
class A{
public:
A(){foo();}
virtual void foo(){cout<<"A.foo()";}
};
class B : public A{
public:
B(){}
void foo(){cout<<"B.foo()";}
};
int main(){
B *b = new B();
}
C#
-回声B.foo()
class A{
public A(){foo();}
public void foo(){System.out.println("A.foo()");}
}
class B extends A{
public void foo(){System.out.println("B.foo()");}
}
class Demo{
public static void main(String args[]){
B b = new B();
}
}
class A{
public A(){foo();}
public virtual void foo(){Console.WriteLine("A.foo()");}
}
class B : A{
public override void foo(){Console.WriteLine("B.foo()");}
}
class MainClass
{
public static void Main (string[] args)
{
B b = new B();
}
}
<>我意识到C++对象是从最高层的父级创建的,所以当构造函数调用重写方法时,B甚至不存在,因此它调用了A方法的版本。但是,我不知道为什么在C++中爪哇和C(从C++)< p>得到不同的行为,正如您正确指出的,对象是类型<代码> a <代码>,直到<代码> A<代码>构造函数完成。对象在其构造过程中实际上会更改类型。这就是为什么使用
A
类的函数,因此调用A::foo()
而不是B::foo()
在Java和C#中,派生类型最多的vtable(或等效机制)贯穿始终,甚至在基类的构造过程中也是如此。因此,在这些语言中,B.foo()
被调用
请注意,通常不建议从构造函数调用虚拟方法。如果不十分小心,虚拟方法可能会假定对象已完全构造,即使事实并非如此。在Java中,每个方法都是隐式虚拟的,您别无选择。虽然我知道您这样做是为了实验,但请务必注意以下引用自《有效Java第二版》第17项:继承的设计和文档,或者禁止它:
类还必须遵守一些限制才能允许继承构造函数不能直接或间接调用可重写方法。如果违反此规则,将导致程序失败。超类构造函数在子类构造函数之前运行,因此子类中的重写方法将在子类构造函数运行之前调用。如果重写方法依赖于子类构造函数执行的任何初始化,则该方法将不会按预期的方式运行 下面是一个例子来说明:
public class ConstructorCallsOverride {
public static void main(String[] args) {
abstract class Base {
Base() { overrideMe(); }
abstract void overrideMe();
}
class Child extends Base {
final int x;
Child(int x) { this.x = x; }
@Override void overrideMe() {
System.out.println(x);
}
}
new Child(42); // prints "0"
}
}
这里,当
Base
构造函数调用overrideMe
时,子项
尚未完成初始化最终整数x
,并且该方法获取了错误的值。这几乎肯定会导致错误和错误。不要在C++构造函数中调用虚函数…这个问题很奇怪。C和C++是不同的语言,所以它们当然有不同的规则。如果他们有相同的规则,那么他们将是相同的语言。为什么C++在java构造函数和模板方法模式上遵循了C++的相关帖子规则:你可以在java中标记方法为“代码>最终< /代码>,这可以防止它们被子类重写。我相信C#(可能是密封的
?)中也有类似的机制。是的,将从构造函数调用的方法(直接或间接)标记为最终的
将是明智的。在C#中不需要类似的机制,因为在C#中,方法只有在明确声明的情况下才是虚拟的。“在Java和C#中,最派生类型的vtable(或等效机制)始终被使用”-请您澄清一下,我知道什么是vtable。“因此子类中的重写方法将被调用”-超类在其构造过程中如何调用子类方法(当子类尚未被构造时)?(我理解上面的例子,子类初始化没有完成,但我希望该方法甚至没有被调用,因为子类还没有被构造)你的问题基于一个错误的假设,即在没有构造派生类对象的情况下无法调用方法。在Java中,它可以。