简体   繁体   English

C ++与Java的多态性

[英]Polymorphism in C++ vs Java

I'm converting some Java code to C++ and I want to keep the class structure similar. 我正在将一些Java代码转换为C ++,并且希望保持类结构相似。 However, I have encountered the following problem, which I don't know how to solve; 但是,我遇到了以下问题,我不知道该如何解决。 I do this in Java: 我在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();
}

will produce: I am the son! 会产生: 我是儿子! While: 而:

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();

will produce I am the father! 会产生我是父亲! . How can I make the C++ code to produce the same result as the Java code? 如何使C ++代码产生与Java代码相同的结果? Thanks. 谢谢。

Daughter 's constructor invokes the Mother constructor, which invokes maker() . Daughter的构造函数调用Mother构造函数, Mother构造函数调用maker() In C++, at least, the object is only considered to be a Mother at this point as the Daughter construction is incomplete. 至少在C ++中,由于Daughter构造不完整,因此在这一点上仅将该对象视为Mother Thus Mother::maker() is invoked, so this is doing the correct thing. 因此,调用了Mother::maker() ,所以这是在做正确的事情。 However, it is generally considered a strong code smell to invoke virtual functions during construction - for exactly these sorts of reasons. 但是,出于这些原因,通常在构造过程中调用虚拟函数被认为是强烈的代码味道。

In Java, apparently the sub-class overrides are always called, even during construction, and as a result constructors in Java should never call overridable methods. 在Java中,显然,即使在构造过程中,始终会调用子类重写,因此,Java中的构造函数绝不应调用可重写方法。 Doing so can lead to undefined behavior. 这样做可能导致不确定的行为。 There is a very nice explanation of this here . 还有就是这是一个非常不错的解释在这里

AFAIK in Java it's only bad style to call a (non-final) method in the constructor, ie, a method which can be overridden in a derived class. 在Java中使用AFAIK时,在构造函数中调用(非最终)方法(这是可以在派生类中重写的方法)是唯一不好的样式。 C++ does always call the actual class' version, not the overridden one. C ++始终会调用实际类的版本,而不是被覆盖的版本。

Can you get around this by passing the object to the constructor? 您可以通过将对象传递给构造函数来解决此问题吗?

You shouldn't call virtual functions from the base class constructor - the derived class' vtable won't have been linked to yet, so you'll always end calling the base class' function. 您不应该从基类构造函数中调用虚函数-派生类的vtable尚未链接到,因此您将始终结束调用基类的函数。 You shouldn't really do this in Java either as while it will call the correct function, the most derived class won't have been instantiated yet - which could lead to undefined behavior. 您也不应该在Java中真正执行此操作,因为它将调用正确的函数,但尚未实例化最多派生的类-这可能导致未定义的行为。 Ultimately, it's wrong in both languages for different reasons. 最终,由于不同的原因,两种语言都是错误的。

One way around this is to have the derived class pass the result of the would-be-virtual call into the base class: 解决此问题的一种方法是让派生类将可能虚拟调用的结果传递给基类:

daughter(): mother(new son) { }

So that: 以便:

mother() : make(new father) { make->print(); }
mother(father * m) : make(m) { make->print(); }

This becomes easier with delegating constructors: 通过委派构造函数,这变得更加容易:

mother()
: mother(new father)
{ }

mother(father* m)
: make(m)
{
    make->print();
}

In C++ calling a virtual function from a base constructor doesn't call the more derived implementation. 在C ++中,从基本构造函数调用虚拟函数不会调用更多派生的实现。 The reason for this is that with a constructor for type BASE the type is BASE , even if the constructor is being called from a derived class, DERIVED . 原因是,对于BASE类型的构造函数,类型是BASE ,即使从派生类DERIVED调用了该构造函数。 Because of this the virtual function table is still being constructed and won't point to the more derived implementation until after the DERIVED constructor has finished executing. 因此,虚拟函数表仍在构建中,直到DERIVED构造函数完成执行后,才指向更派生的实现。

Java (and C#) differ from C++ here as you can call a virtual function from a base constructor, and it will call the most derived implementation. Java(和C#)与C ++的不同之处在于,您可以从基本构造函数中调用虚拟函数,并且它将调用派生程度最高的实现。 However, as the most derived constructor won't have run yet the object may be in an undefined state, and this is why it' not recommended to call virtual functions from constructors. 但是,由于派生程度最高的构造函数尚未运行,因此该对象可能处于未定义状态,这就是为什么不建议从构造函数中调用虚函数的原因。

As to how to get around it, you could add an initialize method which you call after creating your instance. 关于如何解决它,您可以添加一个initialize方法,该方法在创建实例后调用。 As the object will be fully constructed at this point it will call the correct virtual function (in all languages). 由于此时将完全构建对象,因此它将调用正确的虚函数(所有语言)。

When you create a Derived object, it first calls Base's constructor. 创建派生对象时,它首先调用Base的构造函数。 When executing the Base's constructor (Mother), the this object is not yet of type Derived(daughter); 在执行Base的构造函数(Mother)时,此对象还不是Derived(daughter)类型; its type is still merely Base (Mother) Read this for more information: http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctors.html 它的类型仍然仅仅是Base(母亲)。有关详细信息, 阅读此文章: http : //www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctors.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM