为什么在 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"是关键词:)
多态性意味着,如果 Y
是 X
的子类,那么 Y
实际上 是 X
,并且可以用作 X
任何地方。
现在,这意味着,如果 X
有一个方法 void k()
,那么 Y
也必须有相同的方法(否则,您将无法将其用作 X
).但是你不能有两个具有相同签名的不同方法,因此 Y.k()
也必须 return void
(否则,它将是不同的方法)。
在 C++ 的情况下,非虚函数不是多态的:A.k
和 B.k
在这种情况下是两种完全不同的方法,因此没有限制。
简而言之,让我们稍微改变一下您的示例:假设您将 X.k
定义为 return int
,将 Y.k()
定义为 void
.想象这样一个函数:
int plusOne(X x) {
return x.k() + 1
}
这应该可以编译并工作,对吧?但是 plusOne(new Y())
呢?
这也必须有效,因为 Y
是 X
... 但是,如果 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; }
}
#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"是关键词:)
多态性意味着,如果 Y
是 X
的子类,那么 Y
实际上 是 X
,并且可以用作 X
任何地方。
现在,这意味着,如果 X
有一个方法 void k()
,那么 Y
也必须有相同的方法(否则,您将无法将其用作 X
).但是你不能有两个具有相同签名的不同方法,因此 Y.k()
也必须 return void
(否则,它将是不同的方法)。
在 C++ 的情况下,非虚函数不是多态的:A.k
和 B.k
在这种情况下是两种完全不同的方法,因此没有限制。
简而言之,让我们稍微改变一下您的示例:假设您将 X.k
定义为 return int
,将 Y.k()
定义为 void
.想象这样一个函数:
int plusOne(X x) {
return x.k() + 1
}
这应该可以编译并工作,对吧?但是 plusOne(new Y())
呢?
这也必须有效,因为 Y
是 X
... 但是,如果 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; }
}