C ++动态强制转换失败/子对象被视为父对象

时间:2016-11-27 00:24:20

标签: c++ base dynamic-cast derived

我想要的只是Java代码的C ++: if(ParentClassObject.myIdentifier ==“Child1”)   (Child1)ParentClassObject ......做事

所以我想要的就是 - 将我创建的对象作为Child对象 - 在一个不确定它是什么类型的Child的方法中使用它,所以它将它视为父对象 - 将其作为适当的子对象

3个小时后,我无法完成这项工作,我的电脑即将空降。我还阅读了有关OOD的12篇SE文章和教程,但没有找到/不认识解决方案。

在下面的精简代码中,CombatLogLine是Parent,“CombatLogVersionLine”是Child。 determineTypeOfEvent是将其创建为子项的方法,然后将其作为父项返回。完整代码位于https://docs.google.com/document/d/1OXF-YyR0DF0VfdUe9r4OUgPIYNRYXsiMMmQ_fkV-QIQ/edit?usp=sharing

由于某种原因,代码分为两个块,您可能需要向下滚动才能看到第一个块中的所有代码。感兴趣的行中有XXXXXXXXXX。

//CombatLogLine.h
#include stdafx.h
class CombatLogLine
{
    public:
    bool virtual areFieldsOk();
    void virtual parseLine();
    string typeOfEvent;
    //a bunch of stuff I removed

protected:
    string theLineOfRawText;
};

class CombatLogVersionLine : public CombatLogLine 
{
public:
    CombatLogVersionLine(string _theLineOfRawText) : CombatLogLine(_theLineOfRawText)
    {
    typeOfEvent = "COMBAT_LOG_VERSION";
}
bool areFieldsOk();
void parseLine();
private:
};

//CombatLogLine.cpp
#include "stdafx.h"
#include "CombatLogLine.h"

CombatLogLine::CombatLogLine(string _theLineOfRawText)
{
    //stuff I removed for this example involving _theLineOfRawText
    typeOfEvent = "TBA";
}

bool CombatLogLine::areFieldsOk()
{
    cout << "This is the base classes areFieldsOk" << endl;
    return false;
}


bool CombatLogVersionLine::areFieldsOk()
{
    if(typeOfEvent == "COMBAT_LOG_VERSION")
    {
        if(sizeOfLine == 2)
        {
            cout << "Hallelujah!" << endl;
            return true;
        }
    }
    return false;
}

void CombatLogVersionLine::parseLine()
{
}


// main method

....

    for(unsigned int i = 0; i < combatLogSplitIntoLines.size(); i++)
    {   
        CombatLogLine currentLine = determineTypeOfEvent(combatLogSplitIntoLines[i]);//determine type of event also creates an appropriate CombatLogLine 
        if(currentLine.typeOfEvent == "COMBAT_LOG_VERSION")
        {
            currentLine.areFieldsOk();
            cout << "type id " << typeid(currentLine).name() << endl; 
            CombatLogVersionLine * temp5 = dynamic_cast<CombatLogVersionLine *>(&currentLine);   //XXXXXXXXXXXXXXXXX I don't even want to use pointers here but think I have to
            if(temp5 == 0)
            {
            //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX dynamic     cast fails
                cout << "The dynamic cast failed." << endl;
            system("PAUSE");
                return 0;
            }
            temp5->areFieldsOk();
            continue;
        }

...

//method in main file 
CombatLogLine determineTypeOfEvent(string _aLine)
{
    if(_aLine == "")
    {
        cout << "Something went wrong asdghaer" << endl;
        system("PAUSE");
    }
    if(_aLine.find("COMBAT_LOG_VERSION") != string::npos)
    {
        CombatLogVersionLine returnValue(_aLine);
        //XXXXXXXXXXXXXXXXXXXXXXXXXXXXX this works properly and creates a "CombatLogVersionLine"
        cout << "A CombatLogVersionLine was created. " <<     typeid(CombatLogVersionLine).name() << endl;
        return returnValue;
    }
    return (CombatLogLine("FAIL"));
}

1 个答案:

答案 0 :(得分:1)

C ++不是Java。 C ++对象与Java对象根本不同。尝试使用像Java对象这样的C ++对象是保证失败的途径。

您的determineTypeOfEvent()函数返回一个超类:

CombatLogLine determineTypeOfEvent(string _aLine)

它正在构建一个子类,然后尝试返回它:

    CombatLogVersionLine returnValue(_aLine);

    // ...

    return returnValue;

在这里完全停止。不要过去&#34;去&#34;。不要收200美元。 C ++没有这种方式工作。这就是你用Java做事的方式。但这不是你在C ++中做事的方式。在C ++中,这是results in object slicing。该函数不会返回CombatLogVersion子类。在通过其复制构造函数构造CombatLogLine临时变量后,子类立即被销毁,并准确返回此函数声明为返回的内容:CombatLogLine。子类被切掉了。

在继续执行项目之前,您需要花费额外的时间来研究C ++对象和类的工作方式。有几种可能的方法可以正确地执行此操作。通常,在这些情况下,相关函数将返回std::shared_ptr<CombatLogLine>,并在动态范围内构造返回值;以及此函数的所有调用者都相应地使用返回值。

这是做这样的事情的一种方式,但不是唯一的方法。可能在类似情况下使用的另一种可能的替代方案是模板,或者可能传递类型擦除的std::function回调。很难说,这里的正确方法取决于此申请的细节。

这里的一般答案是:&#34; C ++对象不能以这种方式工作,你应该花更多的时间来学习C ++类的工作方式,以及C ++的其余部分语言,其库以及模板,智能指针和函数对象等所有功能,以确定解决问题的最佳方案。 C ++中没有即时的满足感。

您确实需要完全忘记Java对象的工作方式。如果你试图使用C ++对象,认为它们在某种程度上类似于Java对象,那只会让事情变得更加混乱。他们不是。语法,关键字和语法看起来看似相似,但它们完全且根本不同。他们以完全不同的方式工作。