为什么继承在Java和C++;超类调用(或不调用)子类';方法? 我已经写了——在爪哇和C++中,似乎是完全相同的继承例子。看到这些程序的不同输出,我真的很惊讶。让我分享代码片段和相应的输出

为什么继承在Java和C++;超类调用(或不调用)子类';方法? 我已经写了——在爪哇和C++中,似乎是完全相同的继承例子。看到这些程序的不同输出,我真的很惊讶。让我分享代码片段和相应的输出,java,c++,inheritance,Java,C++,Inheritance,C++代码: class A { public: A() {} void sleep() { cout << "A.Sleep" << endl; eat(); } void eat() {cout << "A.Eat" << endl;} }; class B: public A { public: B() {} void s

C++代码:

class A
{
public:
    A() {}
    void sleep() {
        cout << "A.Sleep" << endl;
        eat();
    }
    void eat() {cout << "A.Eat" << endl;}
};

class B: public A
{
public:
    B() {}
    void sleep() {
        A::sleep();
        cout << "B.Sleep " <<endl;
        this->eat();
    }
    void eat() {
        cout << "B.Eat" << endl;
        run();
    }
    void run() {
        A::sleep();
        cout << "B.run" << endl;
    }
};

int main()
{
    B *b = new B();
    b->sleep();
}
A.Sleep
A.Eat
B.Sleep
B.Eat
A.Sleep
A.Eat
B.run

executed successfully...
class A
{
    A() {}
    void sleep() {
        System.out.println("A.Sleep");
        this.eat();
    }
    void eat() { System.out.println("A.Eat");}
};

class B extends A
{
    B() {}
    @Override
    void sleep() {
        super.sleep();
        System.out.println("B.Sleep");
        this.eat();
    }
    @Override
    void eat() {
        System.out.println("B.Eat");
        run();
    }
    void run() {
        super.sleep();
        System.out.println("B.Run");
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        b.sleep();
    }
}
A.Sleep
B.Eat
A.Sleep
B.Eat
A.Sleep
......
......
......
(Exception in thread "main" java.lang.StackOverflowError)

Java代码:

class A
{
public:
    A() {}
    void sleep() {
        cout << "A.Sleep" << endl;
        eat();
    }
    void eat() {cout << "A.Eat" << endl;}
};

class B: public A
{
public:
    B() {}
    void sleep() {
        A::sleep();
        cout << "B.Sleep " <<endl;
        this->eat();
    }
    void eat() {
        cout << "B.Eat" << endl;
        run();
    }
    void run() {
        A::sleep();
        cout << "B.run" << endl;
    }
};

int main()
{
    B *b = new B();
    b->sleep();
}
A.Sleep
A.Eat
B.Sleep
B.Eat
A.Sleep
A.Eat
B.run

executed successfully...
class A
{
    A() {}
    void sleep() {
        System.out.println("A.Sleep");
        this.eat();
    }
    void eat() { System.out.println("A.Eat");}
};

class B extends A
{
    B() {}
    @Override
    void sleep() {
        super.sleep();
        System.out.println("B.Sleep");
        this.eat();
    }
    @Override
    void eat() {
        System.out.println("B.Eat");
        run();
    }
    void run() {
        super.sleep();
        System.out.println("B.Run");
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        b.sleep();
    }
}
A.Sleep
B.Eat
A.Sleep
B.Eat
A.Sleep
......
......
......
(Exception in thread "main" java.lang.StackOverflowError)

输出:

class A
{
public:
    A() {}
    void sleep() {
        cout << "A.Sleep" << endl;
        eat();
    }
    void eat() {cout << "A.Eat" << endl;}
};

class B: public A
{
public:
    B() {}
    void sleep() {
        A::sleep();
        cout << "B.Sleep " <<endl;
        this->eat();
    }
    void eat() {
        cout << "B.Eat" << endl;
        run();
    }
    void run() {
        A::sleep();
        cout << "B.run" << endl;
    }
};

int main()
{
    B *b = new B();
    b->sleep();
}
A.Sleep
A.Eat
B.Sleep
B.Eat
A.Sleep
A.Eat
B.run

executed successfully...
class A
{
    A() {}
    void sleep() {
        System.out.println("A.Sleep");
        this.eat();
    }
    void eat() { System.out.println("A.Eat");}
};

class B extends A
{
    B() {}
    @Override
    void sleep() {
        super.sleep();
        System.out.println("B.Sleep");
        this.eat();
    }
    @Override
    void eat() {
        System.out.println("B.Eat");
        run();
    }
    void run() {
        super.sleep();
        System.out.println("B.Run");
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        b.sleep();
    }
}
A.Sleep
B.Eat
A.Sleep
B.Eat
A.Sleep
......
......
......
(Exception in thread "main" java.lang.StackOverflowError)

我不知道为什么这两个继承的例子表现不同。难道它不应该同样起作用吗


<>强>对这个场景的解释是什么?< /强>

在C++实例中,你是基本方法,但是你不重写它们。所以它们实际上是不同的方法,只是碰巧有相同的名称。如果你打电话

A* a = new B();
a->sleep();
它实际上会打印
“A.Sleep”
。如果要重写方法,则需要在基类中声明它(在所有子类中也会自动使其成为虚拟的)。您可以阅读更多关于函数隐藏与VC++中的重写。


在Java示例中,您实际上重写了这些方法,因此它们是相同的方法。一个代替旧的。您可以这样想:所有Java函数都被秘密标记为
virtual
,这意味着它们可以被重写。如果希望方法在Java中不可重写,则必须声明它。

注意:要小心,每种语言都有自己的思维方式。有很多方法可以解释/实现OO。即使C++和java看起来相似,它们也不太相似。 在这两种语言中,编译器在编译时通过检查类(以及从当前类继承的类等)是否具有正确的签名和可见性,验证是否可以调用方法。使事情不同的是呼叫真正发出的方式

C++

在非虚拟方法的情况下调用的方法在编译时完全确定。这就是为什么即使对象是类
B
,当它执行
A::sleep
时,对
eat
的调用被解析为对
A::eat
的调用(
eat
不是虚拟的,那么编译器调用
A::eat
,因为您处于
A
级别)。在
B::sleep()
中,对
this->eat()
的调用被解析为对
B.eat()
的调用,因为在那里
this
属于
B
类型。您不能进入继承层次结构(在类
A
中调用
eat
将永远不会在下面的类中调用
eat
方法)

请注意,在虚拟方法的情况下情况是不同的(它与Java情况更相似,但不同)

Java

在Java中,调用的方法在运行时确定,并且是与对象实例最相关的方法。因此,在
A.sleep
中,对
eat
的调用将是与当前对象类型相关的调用,这意味着类型
B
(因为当前对象属于类型
B
),然后将调用
B.eat


然后会出现堆栈溢出,因为在处理类型为
B
的对象时,调用
B.sleep()
将调用
a.sleep()
,后者将调用
B.eat()
,后者将调用
B.run()
,后者将调用
a.sleep()
,在Java中,所有方法都是虚拟的(即受重写约束)。在C++中,它们不是。如果给基类中的一个与非虚方法同名的子类,它们只是两个类似命名的方法。我将把标题/问题改成“在这种情况下C++和java继承有什么区别?”,因为为什么?仅仅因为C++和java是两种不同的语言,为什么它不一样呢?在两种不相关的语言之间进行并行通常会适得其反,因为Java中的方法是默认的。“我用Java和C++编写了完全相同的继承示例”-没有。您试图尽可能接近相同的语法(并且没有用重写关键字来实现)。“Cest+'在C++中确实有相同的含义,BTW. @ MalStruts Trtrue,但这仅在基类已经将该方法定义为虚拟时才是必要的。