1

在这个 C++ 程序中,

#include<iostream>
using namespace std;

class Base
{

    public:

    Base()
    {
        cout<<"\n\nBase ctr";
        fun();
    }  

    virtual void fun()
    {
        cout<<"\n\nBase's fun()";
    }
};

class Derived : public Base
{
    public:

    Derived()
    {
        cout<<"\n\nDerived ctr";
        fun();
    }

    virtual void fun()
    {
        cout<<"\n\nDerived's fun()";
    }
};
    int main()
    {
        Derived obj;
        return 0;
    }

当使用 Derived 类对象从 Base 类的构造函数调用虚函数时,会调用 Base 的类 fun(),

输出::
基础 ctr

基地的乐趣()

派生的 ctr

派生的乐趣()

原因在这里解释 但是

在这个java程序中,

class Base
{
    Base()
    {
        System.out.println( "\n\nBase ctr" );
        fun();
    }
    void fun()
    {
        System.out.println( "\n\nBase's fun()" );
    }
}

class Derived extends Base
{
    int a=1;

    Derived()
    {
        System.out.println( "\n\nDerived ctr a = "+a );

        a=8;
        fun();
    }

    void fun()
    {
       System.out.println( "\n\nDerived's fun() a = "+a );
    }

    public static void main(String args[])
    {
       Derived obj = new Derived();
    }
}

输出是 ::
Base ctr

派生的 fun() a = 0

导出 ctr a = 1

派生的 fun() a = 8

这里调用了派生类fun(),所以应用于c++程序的约束,不适用于JAVA程序。为什么?

4

1 回答 1

3

这两种语言采用不同的方法进行动态调度。在 C++ 中,它只会分派给完全构造的对象。这是通过在构造过程中随着层次构造函数的不同级别开始执行而更改对象的类型来处理的。另一方面,Java 甚至在启动最基础的构造函数之前就认为对象是最派生的类型。

Java 方法的问题在于它实际上可能在尚未构造的对象上执行代码。考虑派生类型有一个初始化为 X 的字段,并且它在方法中被访问/更新。在基础对象上调用该方法将在构造函数初始化之前访问该成员。

无论如何,您应该避免在任何一种语言的对象的构造函数或析构函数中调用虚函数。


说明性示例:

public class Base {
   public final int x;
   public Base() { 
      x = foo();
   }
   int foo() { return 1; }
}
public class Derived extends Base {
   public final int y;
   public Derived() {
      y = 2;
   }
   int foo() { return y; }
}
Derived d = new Derived();
assert( d.x == d.y );                      // Can this ever fail?

在这段代码中,我们有 2 个 final int,代码看起来很简单,可以推理。assert会失败吗?

于 2012-05-29T14:25:24.660 回答