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

C++ dynamic cast failing / child object gets treated as parent

我想要的只是 java 代码的 C++ 等价物: 如果(ParentClassObject.myIdentifier == "Child1") (Child1) ParentClassObject ...做事

所以我只想 --把我创建的一个对象作为子对象 -- 在不确定它是什么类型的 Child 的方法中使用它,因此它将它视为 Parent Object --将其转换为适当的子对象

3 小时后我还没有完成这项工作,我的计算机即将空降。我还阅读了很多关于 OOD 的 SE 文章和教程,但没有 find/didn 不认识解决方案。

在下面的精简代码中,CombatLogLine 是父项,"CombatLogVersionLine" 是子项。 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"));
}

C++ 不是 Java。 C++ 对象从根本上不同于 Java 对象。尝试使用像 Java 对象这样的 C++ 对象肯定会导致失败。

您的 determineTypeOfEvent() 函数 return 是一个超类:

CombatLogLine determineTypeOfEvent(string _aLine)

它正在构造一个子类,然后尝试return它:

    CombatLogVersionLine returnValue(_aLine);

    // ...

    return returnValue;

句号就在这里。不要通过"Go"。不要收取 200 美元。 C++ 不是这样工作的。这就是您在 Java 中做事的方式。但这不是你在 C++ 中做事的方式。在 C++ 中,这个 results in object slicing。该函数不会 return 一个 CombatLogVersion 子类。在通过其复制构造函数构造 CombatLogLine 临时对象后,子类立即被销毁,returning 正是这个函数被声明为 returning: CombatLogLine。子类被切掉。

在继续您的项目之前,您需要花额外的时间研究 C++ 对象和 类 的工作原理。有几种可能的方法可以正确地做到这一点。通常,在这种情况下,相关函数将 returning a std::shared_ptr<CombatLogLine>,并在动态范围内构造 return 值;并且此函数的所有调用者都相应地使用 return 值。

这是执行此类操作的一种方法,但不是唯一的方法。在类似情况下可能使用的另一种可能的替代方法是模板,或者可能传递类型擦除的 std::function 回调。很难说,这里正确的方法取决于这个应用程序的细节。

这里的一般答案是:"C++ objects don't work this way, and you should spend more time learning how C++ classes work",以及 C++ 语言的其余部分、它的库和它的所有特性,如模板、智能指针和函数对象,以便为您的问题确定最佳解决方案。在 C++ 中没有即时的满足。

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