C++ vs Java 中的多态性
Polymorphism in C++ vs Java
我正在将一些Java代码转换为C++,我想保持类结构相似。但是,我遇到了以下问题,我不知道如何解决;我在Java中这样做:
public class Mother {
protected Father make;
public Mother(){
make = maker();
make.print(); };
public Father maker(){
return new Father();};}
public class Daughter extends Mother {
public Daughter(){
super();}
@Override
public Father maker(){
return new Son();};}
public class Father {
public void print(){
System.out.println("I am the Father!n");}}
public class Son extends Father {
@Override
public void print(){
System.out.println("I am the son!n");};}
public static void main(String[] args) {
Daughter dot = new Daughter();
}
将产生:我是儿子!而:
class father{
public:
virtual void print(){
std::cout << "I am the father!n";
}; };
class son: public father{
public:
virtual void print(){
std::cout << "I am the son!n";
};};
class mother{
protected:
father *make;
public:
mother(){
make = maker();
make->print();
};
virtual father *maker(){
return new father();
};};
class daughter: public mother{
public:
daughter(): mother() {
};
virtual father *maker(){
return new son();
};};
int main(int argc, const char * argv[]) {
daughter *d = new daughter();
将产生我是父亲!如何使C++代码产生与 Java 代码相同的结果?谢谢。
Daughter
的构造函数调用Mother
构造函数,构造函数调用maker()
。至少在C++中,由于Daughter
构造不完整,因此此时该对象仅被视为Mother
。因此Mother::maker()
被调用,所以这是在做正确的事情。但是,在构造过程中调用虚拟函数通常被认为是一种强烈的代码气味 - 正是出于这些原因。
在 Java 中,显然子类覆盖总是被调用,即使在构造过程中也是如此,因此 Java 中的构造函数永远不应该调用可重写的方法。这样做可能会导致未定义的行为。这里有一个非常好的解释。
Java 中的 AFAIK 在构造函数中调用(非最终)方法只是不好的风格,即可以在派生类中重写的方法。 C++总是调用实际类的版本,而不是被覆盖的版本。
你能通过将对象传递给构造函数来解决这个问题吗?
你不应该从基类构造函数调用虚函数 - 派生类的 vtable 还没有链接到,所以你总是会结束调用基类的函数。你也不应该在 Java 中这样做,因为虽然它会调用正确的函数,但派生最多的类还没有被实例化 - 这可能会导致未定义的行为。最终,由于不同的原因,这两种语言都是错误的。
解决此问题的一种方法是让派生类将虚拟调用的结果传递到基类中:
daughter(): mother(new son) { }
因此:
mother() : make(new father) { make->print(); }
mother(father * m) : make(m) { make->print(); }
通过委派构造函数,这变得更容易:
mother()
: mother(new father)
{ }
mother(father* m)
: make(m)
{
make->print();
}
C++从基构造函数调用虚拟函数不会调用派生的实现。这样做的原因是,对于类型BASE
的构造函数,类型是BASE
的,即使构造函数是从派生类调用的,DERIVED
.因此,虚函数表仍在构造中,并且在DERIVED
构造函数完成执行之前不会指向派生的更多实现。
Java(和 C#)与这里的C++不同,因为您可以从基本构造函数调用虚拟函数,并且它将调用派生最多的实现。但是,由于派生最多的构造函数尚未运行,因此对象可能处于未定义状态,这就是为什么不建议从构造函数调用虚拟函数的原因。
至于如何绕过它,您可以添加一个在创建实例后调用的initialize
方法。由于此时对象将被完全构造,它将调用正确的虚函数(在所有语言中)。
当你创建一个派生对象时,它首先调用 Base 的构造函数。执行 Base 的构造函数 (Mother) 时,this 对象还不是 Derived(daughter) 类型;它的类型仍然只是基地(母亲)阅读此内容以获取更多信息:http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctors.html
- 多态性和功能结合
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- C++boost序列化多态性问题
- 如何查找哪个类对象位于数组的特定索引上(多态性)
- 如何在多线程中正确使用unique_ptr进行多态性?
- 具有智能指针的多态性
- 在 C++ 中在堆栈上创建实例时如何保持多态性?
- 继承/多态性 - 我是否被迫使用"protected"变量?
- C++ 多态性在代码::块 17.12 中不起作用
- C++ 泛型和多态性:这种模式可行吗?
- 为什么我们实际上需要运行时多态性?
- 如何在这个简单的最小示例中实现多态性?
- JAVA和C++中的多态性相同吗?
- C++中的Java多态性
- C++ vs Java 中的多态性
- C++等价于简单的Java多态性
- 多态性?C++与Java
- c++与java中运行时多态性的成本比较
- 使用指示器的c++和Java之间SWIG多态性中的内存泄漏