如何解决Java最终方法与C ++非虚函数
| java final方法和c ++非虚拟方法是不同还是相同?怎么样?解决方法
您仍然可以在C ++的继承类中声明具有相同签名的非虚拟成员函数,而Java明确禁止声明具有相同签名的方法,而基类在该方法中将方法声明为final。在处理继承/多态性时,C ++中的虚拟性仅有助于找到要调用的正确函数。
例:
#include <iostream>
class Base
{
public:
void doIt()
{
std::cout << \"from Base.doIt()\" << std::endl;
}
};
class Child : public Base
{
public:
void doIt()
{
std::cout << \"from Child.doIt()\" << std::endl;
}
};
int main()
{
Base a;
a.doIt(); // calls Base.doIt()
Child b;
b.doIt(); // calls Child.doIt()
Base *c = new Base();
c->doIt(); // calls Base.doIt()
Child *d = new Child();
d->doIt(); // calls Child.doIt()
Base *e = new Child();
e->doIt(); // calls Base.doIt()
std::cin.ignore();
return 0;
}
Java中使用final的可比较示例将导致编译器错误:
public class Base
{
public final void doIt()
{
System.out.println(\"In Base.doIt()\");
}
}
public class Child extends Base
{
public void doIt() // compiler error: Cannot overload the final method from Base
{
System.out.println(\"In Child.doIt()\");
}
}
有关C ++中多态性的更多说明,请参见cplusplus.com:多态性
实际上,这两种方法都有相似的目标:防止在基类中重写函数。他们只是以略有不同的方式进行处理。
,他们是不同的。
C ++非虚拟方法不会被分派,并且不会覆盖任何内容。
调度Java final方法,并且可以在其类的超类中重写方法。
但是,就C ++非虚拟方法或Java final方法都不能重写而言,它们是相似的。从某种意义上说,它们也是相似的,如果您有某个对象的静态类型是所讨论的类型,则运行时系统无需调度该方法调用。
为了说明不同之处,请考虑以下两个Java类:
public class A {
public String toString() {
return \"A\";
}
}
public class B extends A {
public final String toString() {
return \"B\";
}
}
A a = ...
B b = ...
a.toString(); // could call A.toString() or B.toString() - dispatch
b.toString(); // could only call B.toString() - no dispatch required
// but it will behave the same as if dispatching had occurred.
在B :: toString()是非虚拟的C ++等效语言中,我相信a.toString()
无法分派给B::toString()
。 (我对C ++有点生锈...)
(实际上,Java JIT编译器能够检测到不需要虚拟调度的情况……而无需将类或方法声明为final
。因此,ѭ5the的真正目的是指定不得重写方法或类不得扩展...,并请Java编译器为您检查)。
,他们是非常不同的,实际上,我想说,是完全无关的。
在C ++中,如果基类具有非虚拟成员函数,则可以在派生类中声明具有相同名称的非虚拟成员函数。结果是派生类的成员函数将隐藏基类的成员函数。并且不会发生虚拟调度。如下所示:
struct Base {
void foo() {
std::cout << \"Base::foo called!\" << std::endl;
};
};
struct Derived : Base {
void foo() {
std::cout << \"Derived::foo called!\" << std::endl;
};
};
int main() {
Derived d;
d.foo(); //OUTPUT: \"Derived::foo called!\"
Base* b = &d;
b->foo(); //OUTPUT: \"Base::foo called!\"
};
上面显示了派生类的成员函数如何隐藏基类函数。如果您有一个指向基类的指针,则由于这些函数是非虚拟的,因此不会使用虚拟表来解析该调用,因此将调用基类中的foo函数。这里的重点是,在C ++中,没有什么可以阻止您在具有相同名称的Derived类中创建另一个函数(请注意,不同的签名仍将导致所有具有相同名称的基类成员函数的隐藏)。您将得到的只是一个编译器警告,告诉您Derived类的成员函数隐藏了Base类的成员函数。
Java中的最终成员函数完全不同。在Java中,所有成员函数都是虚拟的。因此,您无法像在C ++中一样关闭虚拟调度。最终成员函数只是意味着不允许任何后续的派生类(将发生错误)声明具有相同名称(和签名)的成员函数。但是,在声明原始成员函数的接口/基类与将其标记为final的派生类之间仍然存在虚拟调度(因此,在动态多态意义上是覆盖)。只是严格禁止以后重写该函数(即,尝试在基类中将foo()标记为final的上述代码会在Derived类的声明中产生错误,因为foo()不会允许)。
如您所见,这两个概念完全不同。
在C ++中,使用非虚拟成员函数时,不会发生虚拟分派(因此,传统意义上没有\“ overriding \”),但是允许您使用具有相同名称的成员函数的派生类。有时在“静态多态”中很有用)。
在Java中,使用最终成员函数,仍然会进行虚拟调度,但是严格禁止在后续派生类中进行重写。
,C ++使用虚函数与非虚函数可以产生性能差异,相反,Java中可能没有性能差异。在Java中,将方法标记为“ 5”是纯粹关于代码的清晰度和可维护性(这不是默认行为,相对很少使用),而在C ++中,非虚函数是默认行为,并且在某种程度上通常被使用,部分原因是因为它们具有更好的性能。性能特点。
在Java中,所生成的代码可能因使用方式而异,而C ++必须在编译时产生正确性。
例如如果JVM检测到\“ virtual \”方法仅具有一个或两个常用的实现,则可以内联这些方法或将\“ virtual \”方法仅使用一个实现作为最终方法对待。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。