#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.
}
}
为什么我们不能更改子类或子类中的返回类型?
答案 0 :(得分:4)
你猜对了,&#34;多态&#34;是关键词:)
多态性意味着,如果X
是Y
的子类,那么X
有效是 X
,并且可以用作X
任何地方。
现在,这意味着,如果void k()
有方法Y
,那么X
也必须使用相同的方法(否则,您将无法将其用作{{1} }})。但是你不能有两个不同的方法使用相同的签名,因此Y.k()
也必须返回void
(否则,它将是一个不同的方法)。
在C ++案例中,非虚函数不具有多态性:A.k
和B.k
是两种完全不同的方法,因此没有限制。
简单来说,让我们稍微更改一下您的示例:假设您将X.k
定义为int
,将Y.k()
定义为void
。想象一下这样的函数:
int plusOne(X x) {
return x.k() + 1
}
这应该编译和工作,对吗?但是plusOne(new Y())
呢?
这也必须有效,因为Y
是X
...但是,如果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; }
}