我有一些C++的背景知识,也知道一些Java(显然远远不够).
当我在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 } }
在Java中,您使用基类引用,在C++中您使用基类指针,并依赖于它指向的实例类型(基类对象实例或子类实例),您可以实现多态.
以上是基于您使用基类引用或指针调用实例方法,对吧?
现在我在Java中看到这个例子.
本Java代码中构造函数的顺序是什么?
基本上它说如果基类函数被覆盖,那么在创建子类对象的过程中,甚至基类初始化部分也会受到影响.请参阅以下我从上面链接复制的说明:
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 doc http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.5中,我只发现了这个:
"与C++不同,Java编程语言在创建新类实例期间没有为方法分派指定更改的规则.如果调用的方法在被初始化的对象的子类中被覆盖,则使用这些覆盖方法,甚至在新对象已完全初始化."
但我不知道背后的原因,感觉很奇怪.
有什么想法吗?
这是极少数情况下,C++试图保护你不要像Java那样用脚射击自己.(或者至少它有这样做的崇高意图.)
如果你尝试从B的构造函数中调用基类B的可覆盖(虚拟)方法M,那么你很有可能用任何语言开始自己.这是因为M很可能在派生类D中被覆盖,但是在B正在建造的那一刻,D尚未建成.因此,在调用D的构造函数之前调用DM.这可能会造成灾难.
因此,Java只允许这种情况发生,使用风险自负.(如果启用了足够的警告,编译器会告诉您危险的生活.)
C++也没有禁止这一点,但它稍微改变了它的行为以便包含损坏,可以这么说:当你从构造函数中调用虚方法时,它并不真正将它作为虚方法调用(使用VMT)查找,但它直接调用它,作为非虚方法.
(无论是那个,还是从B的构造函数中,它只是使用B类的VMT而不是D的VMT.现在来想想它是有道理的.但是我不确定,我已经很久了最后麻烦这个C++的行为.)