为什么在 Java 和 C++ 中不允许隐藏虚拟 functions/methods?

Why isn't hiding of virtual functions/methods allowed in Java and C++?

#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 的功能更改为虚拟时,它说 return 类型应该相同,为什么?

我在 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 当我在子 class 中尝试不同的 return 类型时也显示错误。 (我认为因为默认情况下所有实例方法默认都是虚拟的)我期待 int k() 应该隐藏 void k() 并且 int k() 应该从 Y 的对象调用。

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

如果是多态行为问题。那我觉得object就够确定函数调用了。

示例:

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.
    }
}

为什么我们不能更改 return 子 class 或子 class 类型?

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

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

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

If it polymorphic behavior problem. Then I think object is enough to determined the function calling

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

why we can't change return type in sub-class or child class?

想想下面的例子,(为了便于解释,我对你的示例代码做了一些关于 return 类型的改动)

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;
}

通过基础class指针(或引用)调用虚函数f(),一个int应该是returned,但是根据结果动态调度,B::k() 实际上会被调用,但它会 return 一个完全不同的类型(即 std::string)。它自相矛盾且格式错误。

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

The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions.

你猜对了,"polymorphic"是关键词:) 多态性意味着,如果 YX 的子类,那么 Y 实际上 X,并且可以用作 X任何地方。

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

在 C++ 的情况下,非虚函数不是多态的:A.kB.k 在这种情况下是两种完全不同的方法,因此没有限制。

简而言之,让我们稍微改变一下您的示例:假设您将 X.k 定义为 return int,将 Y.k() 定义为 void.想象这样一个函数:

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

这应该可以编译并工作,对吧?但是 plusOne(new Y()) 呢? 这也必须有效,因为 YX ... 但是,如果 Y.k() 到 return 可能是空的,那么 plusOne 会做什么是吗?

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

Java 方法和 C++ 虚函数 可以 被隐藏,但是不同的 return 类型 允许的覆盖,只要它们兼容。只有 冲突 return 类型是不允许的。例如,在 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; }
}