为什么不隐藏Java和C ++中允许的虚函数/方法?

时间:2016-03-12 14:19:42

标签: java c++ override

#include <iostream>
class A{
    public:
        void k(){
            std::cout << "k from A";
        }
};
class B:public A{
    public:
        int k(){
            std::cout << "k from B"; 
            return 0;
        }
};
int main(){
    B obj;
    obj.k();

    return 0;
}

没有虚拟,它工作正常,但当我将A的功能更改为虚拟时,它说返回类型应该是相同的原因?

我在Java中尝试过同样的事情:

class X{
    public void k(){
        System.out.println("k From X");
    }
}
public class Y{
    public int k(){
        System.out.println("k From Y");
        return 0;
    }
}

当我在子类中尝试不同的返回类型时,Java也显示错误。 (我认为,因为默认情况下默认情况下所有实例方法都是虚拟的)我希望int k()应该隐藏void k()int k()应该从Y对象调用。

所以我认为这是虚拟问题。当函数声明为virtual时,为什么子类应该使用相同的返回类型?

如果是多态行为问题。然后我认为对象足以确定函数调用。

示例:

class X{
    public void k(){
        System.out.println("k From X");
    }
}
public class Y extends X{
    public int k(){
        System.out.println("k From Y");
        return 0;
    }
    public static void main(String[] args){
        X obj=new Y();
        obj.k(); // object Y found now just call k() from Y.
    }
}

为什么我们不能更改子类或子类中的返回类型?

4 个答案:

答案 0 :(得分:4)

你猜对了,&#34;多态&#34;是关键词:) 多态性意味着,如果XY的子类,那么X有效 X,并且可以用作X任何地方。

现在,这意味着,如果void k()有方法Y,那么X也必须使用相同的方法(否则,您将无法将其用作{{1} }})。但是你不能有两个不同的方法使用相同的签名,因此Y.k()也必须返回void(否则,它将是一个不同的方法)。

在C ++案例中,非虚函数不具有多态性:A.kB.k是两种完全不同的方法,因此没有限制。

简单来说,让我们稍微更改一下您的示例:假设您将X.k定义为int,将Y.k()定义为void 。想象一下这样的函数:

     int plusOne(X x) {
        return x.k() + 1
     }

这应该编译和工作,对吗?但是plusOne(new Y())呢? 这也必须有效,因为YX ...但是,如果Y.k()有可能返回空格,plusOne会对它做什么?

答案 1 :(得分:3)

  

如果是多态行为问题。然后我认为对象足以确定调用函数

动态多态在运行时发生,但返回值的类型在编译时确定。

  

为什么我们不能改变子类或子类中的返回类型?

考虑以下示例,(为方便解释,我更改了一些关于返回类型的示例代码)

class A{
    public:
        virtual int k(){  // returns int
            std::cout << "k from A";
            return 0;
        }
};
class B:public A{
    public:
        std::string k(){  // returns std::string
            std::cout << "k from B";
            return std::string();
        }
};
int main(){
    A* pa = new B;
    int r = pa->k(); // r is supposed to be int, the type is deduced at compile time

    delete pa;
    return 0;
}

通过基类指针(或引用)调用虚函数f(),应该返回int,但根据动态调度的结果,将调用B::k()事实上,它会返回一个完全不同的类型(即std::string)。这是相互冲突和形成不良的。

来自c ++标准,$ 10.3 / 7虚函数[class.virtual]

  

覆盖函数的返回类型应与...相同   被重写函数的返回类型或与变量的协变   功能的类。

答案 2 :(得分:2)

C ++的虚函数是类的接口的一部分,而非虚函数也可能是 implementation 的一部分。扩展类时,告诉编译器您将遵守其所有接口,包括其虚函数的签名。

所有非私有/非最终Java方法都是虚拟的,因此相同的参数适用于它们。

只要对象类型足以确定要调用的方法,您可能不一定在编译时知道类型。编译器必须确定通过静态类型查找方法的方式,包括虚拟查找。这要求编译器知道签名和返回类型。

答案 3 :(得分:0)

当我已经gave you the answer here时,我不知道你为什么再次发布这个问题。但这里再次是正确的答案。

可以隐藏Java方法和C ++虚拟函数 ,但是在覆盖时允许 ,只要它们兼容。它只是冲突的不允许的返回类型。例如,在C ++中:

struct Base {
    virtual Base* f() { return nullptr; }
};

struct Derived : Base {
    Derived* f() override { return nullptr; }
};

在Java中:

class Base {
    Base f() { return null; }
}

class Derived extends Base {
    @Override
    Derived f() { return null; }
}