Java与C ++中的函数重写

时间:2015-06-17 06:12:40

标签: java c++ polymorphism override

Java和C ++中有两个相似的定义,但行为完全不同。

Java版:

class base{
    public void func1(){
        func2();
    }
    public void func2(){
        System.out.println(" I am in base:func2() \n");
    }

}

class derived extends base{
    public void func1(){
        super.func1();
    }
    public void func2(){
        System.out.println(" I am in derived:func2() \n");
    }
};
public class Test
{
    public static void main(String[] args){
        derived d = new derived();
        d.func1();
    }
}

输出:

I am in derived:func2()

C ++版本:

#include <stdio.h>

class base
{
    public:
        void func1(){
            func2();
        }
        void func2(){
            printf(" I am in base:func2() \n");
        }
};

class derived : public base
{
    public:
        void func1(){
            base::func1();
        }
        void func2(){
            printf(" I am in derived:func2() \n");
        }
};

int main()
{
    derived *d = new derived();
    d->func1();
    return 0;
}

输出:

I am in base:func2()

我不知道为什么他们有不同的行为。

即使我知道Java也有自动多态行为。

Java输出很难理解。

在我看来,根据static scope,基类函数func1()应该只能调用基类函数func2(),因为它对派生的一无所知一点上课。否则,调用行为属于dynamic scope。 也许在C ++中,基类中的func2()是绑定static,但在Java中它是绑定dynamic

成员字段是静态范围的。

类型推断部分令人困惑。 我认为this中的base已转换为base::func1()类型。在C ++中,base::func2()不是多态,因此调用base::func1()。 在Java中,base::func2()是多态的,因此调用devried::func2()

如何推断出func2()类绑定?要么 应该调用哪个fun2()以及如何确定它。

base::func1()背后发生了什么? this(从derivebase)是否有任何演员? 如果不是,this如何能够访问base类中的函数?

        void func1(){
            func2();
        }
关于coderanch的

Useful discussion

2 个答案:

答案 0 :(得分:21)

在Java中,所有可以覆盖的方法都自动virtual。没有选择加入机制(virtual关键字),因为它在C ++中(并且也无法选择退出)。

Java的行为就像您已将base::func2声明为

virtual void func2(){
    printf(" I am in base:func2() \n");
}

在这种情况下,您的程序会打印"I am in derived:func2()"

  

如何推断func2()类绑定?
  应该调用哪个fun2()以及如何确定它。

对于非虚方法(没有virtual修饰符的C ++方法),静态类型确定要调用的方法。变量的静态类型由变量声明确定,并不依赖于代码的执行方式。

对于虚方法(使用virtual修饰符和所有 Java方法的C ++方法),运行时类型确定要调用的方法。运行时类型是运行时实际对象的类型。

示例:如果您有

Fruit f = new Banana();

f的静态类型为Fruitf的运行时类型为Banana

如果您执行f.someNonVirtualMethod(),将使用静态类型并调用Fruit::someNonVirtualMethod。如果执行f.someVirtualMethod(),将使用运行时类型并调用Banana::someVirtualMethod

编译器如何实现此目标的基础实现基本上取决于实现,但通常使用vtable。有关详细信息,请参阅

  

如果不是,this如何在base班级中找到该功能?

void func1(){
    func2();
}

如果您想知道为什么func2()在此处拨打base&#39; func2,那是因为

A)您属于base范围,这意味着this的静态类型为base

B)func2中的base 虚拟,因此它是决定调用哪个实现的静态类型。

答案 1 :(得分:0)

在C ++ 中,只有声明为virtual 的情况下,您才能覆盖基类函数。因为在您的c ++示例中,您尚未将'func2()'声明为virtual,所以派生类'func2()'并未覆盖它。

在Java中,您无需在基类中将函数声明为虚函数即可覆盖它们。

考虑这个Java示例。

class Base{
  public void func2(){
    System.out.println("Base class func2()");
  }
}

class Derived extends Base{
  public void func2(){
    System.out.println("Derived class func2()");
  }
}

class Main extends Base{
  public static void main(String[] args) {
    Derived derived = new Derived();
    derived.func2();

    Base base = new Derived();
    base.func2();
  }
}

输出

Derived class func2()
Derived class func2()

如果要在Java中将基类函数声明为非虚函数,则将该函数声明为final。这样可以防止在派生类中重写基类函数。

示例:

class Base{
  public final void func2(){
    System.out.println("Base class func2()");
  }
}

某些外部链接属于我的网站。