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
(从derive
到base
)是否有任何演员?
如果不是,this
如何能够访问base
类中的函数?
void func1(){
func2();
}
关于coderanch的
答案 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
的静态类型为Fruit
,f
的运行时类型为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()");
}
}
某些外部链接属于我的网站。