为什么JAVA中的重写与C++;? 我有一些C++背景,也知道一些java(显然远远不够)。p> 当我看到java或C++中的重写行为时,它似乎没有太大的区别。给出以下JAVA示例: class Animal{ public void move(){ System.out.println("Animals can move"); } } class Dog extends Animal{ public void move(){ System.out.println("Dogs can walk and run"); } } public class TestDog{ public static void main(String args[]){ Animal a = new Animal(); // Animal reference and object Animal b = new Dog(); // Animal reference but Dog object a.move();// runs the method in Animal class b.move();//Runs the method in Dog class } } 爪哇中,使用基类引用,在C++中使用基类指针,并根据它指向的实例类型(基类对象实例或子类实例),可以实现多态性。
以上是基于您使用基类引用或指针调用实例方法,对吗 现在我在Java中看到了这个例子 基本上它说如果基类函数被重写,那么在创建子类对象的过程中,甚至基类初始化部分也会受到影响。请参阅我从上述链接复制的以下说明:为什么JAVA中的重写与C++;? 我有一些C++背景,也知道一些java(显然远远不够)。p> 当我看到java或C++中的重写行为时,它似乎没有太大的区别。给出以下JAVA示例: class Animal{ public void move(){ System.out.println("Animals can move"); } } class Dog extends Animal{ public void move(){ System.out.println("Dogs can walk and run"); } } public class TestDog{ public static void main(String args[]){ Animal a = new Animal(); // Animal reference and object Animal b = new Dog(); // Animal reference but Dog object a.move();// runs the method in Animal class b.move();//Runs the method in Dog class } } 爪哇中,使用基类引用,在C++中使用基类指针,并根据它指向的实例类型(基类对象实例或子类实例),可以实现多态性。,java,c++,Java,C++,以上是基于您使用基类引用或指针调用实例方法,对吗 现在我在Java中看到了这个例子 基本上它说如果基类函数被重写,那么在创建子类对象的过程中,甚至基类初始化部分也会受到影响。请参阅我从上述链接复制的以下说明: new Son() => Son._init => first every constructor calls super() Father._init Object._init who() => is
new Son()
=>
Son._init
=> first every constructor calls super()
Father._init
Object._init
who() => is overridden, so prints "son" !!!!!
tell(name) => name is private, so cannot be overridden => "father"
who() => "son"
tell(name) => "son"
为什么会这样?我的意思是,这是否符合多态性的使用方式?当使基类成为初始化的一部分时,为什么要使用子类中的重写函数
在Java文档中,我只找到以下内容:
“与C++不同,java编程语言在创建新类实例时没有指定用于方法调度的更改规则。如果调用的方法在初始化对象中的子类中被重写,那么在新对象完全初始化之前,使用这些重写方法。”
但我不知道背后的原因,感觉很奇怪有什么想法吗这是极少数情况下,C++试图保护你不让自己在java中射击。(或者至少它有这样做的崇高意图。) 如果您试图从B的构造函数中调用基类B的可重写(虚拟)方法M,则很可能会在任何语言中攻击自己。这是因为M很可能在派生类D中被重写,但在构造B的那一刻,D还没有被构造。因此,在调用D的构造函数之前调用D.M。这可能意味着灾难 因此,Java只是允许这种情况发生,使用风险自负。(如果启用了足够的警告,编译器将告诉您您的生活很危险。) C++也没有禁止这一点,但它稍微改变了它的行为以控制损害,也就是说:当您从构造函数中调用一个虚拟方法时,它实际上并没有将其作为虚拟方法(使用VMT查找)调用,而是直接将其作为非虚拟方法调用
(或者,或者从B的构造函数中,它只使用B类的VMT,而不是D的VMT。现在,开始考虑它是有意义的。但是我不确定,自从我上次排除C++的行为以来,已经有很长的时间了。)< java > C++ C++是两种非常不同的语言,语义不同,java比C++小15年,在虚拟机上运行。一些比较:对于继承,你需要使用<代码>保护< /代码>。如果你想重写,请参阅参考文献:该引用是典型的java炒作。是的,最派生类中的函数总是被调用,这就是“不指定更改的规则”所指的。它忽略的是Java确实改变了规则,在本例中是初始化规则。在派生类中,所有字段都初始化为0;在大多数派生类的构造函数运行之前,它们不会获得实际的初始化值。因此,重写函数必须对零初始化和您编写的初始化都正确工作。很好的解释。谢谢。正式规则是进行虚拟调用,但对象的类型是其构造函数当前正在运行的类型。这与非虚拟通话有着微妙的区别。如果您的类层次结构为
Base
,Intermediate
,MostDerived
,并且Intermediate
的构造函数调用调用虚拟函数的Base
成员函数,您将得到该函数的Intermediate
版本。非虚拟呼叫将获得Base
。这并不常见,但有时确实会发生。@PeteBecker谢谢你的澄清。那么,你会说我在答案末尾的括号里写的是正确的吗?@MikeNakis-基本上,尽管它是关于实现技术而不是需求的。很多人都是这样想的。