Java 中的函数重写与C++

2022-09-03 06:05:11

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输出很难理解。

在我看来,根据静态作用域,基类函数 func1() 应该只能调用基类函数 func2(),因为它对派生类一无所知。否则,调用行为属于动态范围。也许在C++中,基类中的func2()是绑定静态的,但在Java中它是绑定动态的

成员字段是静态范围的。


类型推断部分令人困惑。我以为是转换为键入.在C++中,不是多态性,所以被称为。而在Java中,是多态性,所以被称为。thisbasebase::func1()base::func2()base::func1()base::func2()devried::func2()

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

后面发生了什么?这里有没有(从到)的演员?如果不是,如何能够在课堂上达到函数?base::func1()thisderivebasethisbase

        void func1(){
            func2();
        }

关于代码ranch的有用讨论


答案 1

在Java中,所有可以重写的方法都是自动虚拟的。它没有选择加入机制(关键字),因为它C++(也没有办法选择退出)。virtual

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

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

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

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

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

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

例:如果您有

Fruit f = new Banana();

的静态类型 和 的运行时类型为 。fFruitfBanana

如果这样做,将使用静态类型并调用该类型。如果这样做,将使用运行时类型并调用该类型。f.someNonVirtualMethod()Fruit::someNonVirtualMethodf.someVirtualMethod()Banana::someVirtualMethod

编译器如何实现这一点的基础实现基本上是依赖于实现的,但通常使用vtable。有关详细信息,请参阅


如果不是,如何能够在课堂上达到函数?thisbase

void func1(){
    func2();
}

如果你想知道为什么在这里打电话,那是因为func2()basefunc2

A) 您在其范围内,这意味着 的静态类型是 , 并且basethisbase

B) in 不是虚拟的,因此它是静态类型决定调用哪个实现。func2base


答案 2

在 C++如果基类函数被声明为 virtual,则只能重写该函数。因为在你的c ++示例中,你没有将'func2()'声明为虚拟的,所以它没有被派生类'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()");
  }
}

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


推荐