首页 > 解决方案 > C++:继承和列表函数作为类成员的问题

问题描述

这个问题在某种程度上是我之前提出的问题的后续问题,因为我正在尝试理解和实施建议的概念。我已将所有内容重构为更小的类,并且武器的整体设计已经完成(并在一定程度上实现了)。但是,我在访问一些成员时遇到了问题,我相信一旦这个障碍被克服,我完成这个项目不会有任何问题,因为很多子类都使用类似的系统。

关于我的问题,我有一个父类,部分虚拟类,定义如下:

class ModeInformation {


public:
    ModeInformation() { m_CreateModes(); m_CreateModeChoiceList(); } // These two functions are always called when an object belonging to the ModeInformation parent class is created, as they store elements in two lists, one in which the pointer-to-Modes themselves are stored, the other where Menu options are stored according to the number of modes
    virtual ~ModeInformation() {}

// Modes of a Weapon (virtual as they might be overridden in child classes)
    virtual Mode* pMode1() const { return NULL; }
    virtual Mode* pMode2() const { return NULL; }
    virtual Mode* pMode3() const { return NULL; }
    virtual Mode* pMode4() const { return NULL; }
    virtual Mode* pMode5() const { return NULL; }

// Lists mentioned earlier 
    virtual list<string>* ModeChoiceList() const { return new list<string>; }
    virtual list<Mode*>* Modes() const { return new list<Mode*>; };

// m_CreateModes() stores pointers-to-Mode in Modes(), if these are not NULL
    void m_CreateModes() {
        if (!pMode1() == NULL) { Modes()->push_back(pMode1()); }
        if (!pMode2() == NULL) { Modes()->push_back(pMode2()); }
        if (!pMode3() == NULL) { Modes()->push_back(pMode3()); }
        if (!pMode4() == NULL) { Modes()->push_back(pMode4()); }
        if (!pMode5() == NULL) { Modes()->push_back(pMode5()); }
    }

// m_CreateModeChoiceList() stores strings in ModeChoiceList(), composed using the sstring library. Also a source of problems, as I will point out later on.
    void m_CreateModeChoiceList() {
        int i = 1;
        for (list<Mode*>::iterator it = Modes()->begin(); it != Modes()->end(); it++) {
            stringstream ChoiceDeclaration;
            ChoiceDeclaration << "\n" << i << ".- Mode " << i;
            ModeChoiceList()->push_back(ChoiceDeclaration.str());
            i++;
        }
        ModeChoiceList()->push_back("\n0.- Quit to previous menu.");
    }

// m_PrintBasicInfo() is called from classes that possess an object pertaining to the ModeInformation class (or derived child-classes), serves as a decision tree to judge whether the Mode List should be printed (in the case the Weapon being printed possesses more than one Mode), otherwise it will print the very first Mode
    void m_PrintBasicInfo() {
        if (Modes()->size() > 1) {
            m_PrintModeList();
            m_ChooseModeFromList();
        }
        else {
            pMode1()->m_PrintBasicInfo(1);
        }
    }

// m_PrintModeList() prints each of the elements stored in ModeChoiceList()
    void m_PrintModeList() {
        list<string>::iterator it = ModeChoiceList()->begin();
        while (it != ModeChoiceList()->end()) {
            cout << *it << endl;
            it++;
        }
    }

// m_ChooseModeFromList() provides a dynamic method for a user to choose which Mode's information will be printed
    virtual void m_ChooseModeFromList() {
        int Input = 0;
        cout << "Please input your choice." << endl;
        cin >> Input;
        cout << endl;
        list<Mode*>::iterator it = Modes()->begin();
        switch (Input) {
        case 1: if (it != Modes()->end()) { (*it)->m_PrintBasicInfo(Input); it++; break; }
                else { m_ChooseInvalidModeFromList(); break; }
        case 2: if (it != Modes()->end()) { (*it)->m_PrintBasicInfo(Input); it++; break; }
                else { m_ChooseInvalidModeFromList(); break; }
        case 3: if (it != Modes()->end()) { (*it)->m_PrintBasicInfo(Input); it++; break; }
                else { m_ChooseInvalidModeFromList(); break; }
        case 4: if (it != Modes()->end()) { (*it)->m_PrintBasicInfo(Input); it++; break; }
                else { m_ChooseInvalidModeFromList(); break; }
        case 5: if (it != Modes()->end()) { (*it)->m_PrintBasicInfo(Input); it++; break; }
                else { m_ChooseInvalidModeFromList(); break; }
        case 0: cout << "Returning to previous menu..." << endl; break;
        default: m_ChooseInvalidModeFromList(); break;
        }
    }

// m_ChooseInvalidModeFromList() prints an invalid option message, and returns to m_ChooseModeFromList()
    void m_ChooseInvalidModeFromList() {
        cout << "Invalid option. Please choose a valid mode." << endl;
        m_ChooseModeFromList();
    }
};

我还有一个示例子类,属于武器,我用它来测试代码的可行性和执行。详细如下:

class RailGunModeInformation : public ModeInformation {
public:
    Mode* pMode1() const { return new RailGunMode1(); }
    Mode* pMode2() const { return new RailGunMode2(); }
    list<string>* ModeChoiceList() const { return new list<string>; }
    list<Mode*>* Modes() const { return new list<Mode*>; }
};

现在,它可以编译,但我不断收到“Factory Method.exe 中 0x0FC3CAB6 (ucrtbased.dll) 处的未处理异常:将无效参数传递给认为无效参数致命的函数”。错误。无论我在保持其整体功能的同时尝试对其进行多少修改,我似乎都无法使其正常工作,并出现大量不同的错误。所以我想我会向专家寻求帮助,因为我已经花了几个小时把头撞在墙上试图跳过这个障碍。

标签: c++listclassinheritance

解决方案


你的第一个问题是这个

void m_CreateModes() {
    if (!pMode1() == NULL) { Modes()->push_back(pMode1()); }
    if (!pMode2() == NULL) { Modes()->push_back(pMode2()); }
    if (!pMode3() == NULL) { Modes()->push_back(pMode3()); }
    if (!pMode4() == NULL) { Modes()->push_back(pMode4()); }
    if (!pMode5() == NULL) { Modes()->push_back(pMode5()); }
}

正如评论中提到的 Modes() 每次都返回一个新列表,但 puch_back 的结果在下一个“}”之后不可访问

我将只使用 C++11 来删除代码中一些更繁琐的方面。

using ModeList = list<Mode*>;

ModeList m_CreateModes() {
    ModeList modes = Modes();
    if (!pMode1() == NULL) { modes->push_back(pMode1()); }
    if (!pMode2() == NULL) { modes->push_back(pMode2()); }
    if (!pMode3() == NULL) { modes->push_back(pMode3()); }
    if (!pMode4() == NULL) { modes->push_back(pMode4()); }
    if (!pMode5() == NULL) { modes->push_back(pMode5()); }
    return modes;
}

现在模式一直存在,直到函数退出并返回,调用者现在必须存储返回的值,否则信息会丢失。或者,如果您想重用返回的值,则模式可以是基类的成员变量。

其他问题,这可能会被误解

    if (!pMode1() == NULL) { modes->push_back(pMode1()); }

假设 pMode1() 返回 NULL,然后你得到并且 NULL 被定义为 (0)

    if (!NULL == NULL) { Modes()->push_back(pMode1()); }

    if (true == 0) { Modes()->push_back(pMode1()); }

如果它返回的东西不是 NULL

    if (!0xdeadbeef == NULL) { Modes()->push_back(pMode1()); }

    if (false == 0) { Modes()->push_back(pMode1()); }

所以你真正想要的是,用 nullptr (C++11) 替换 NULL

    if (!pMode1() == nullptr ) { modes->push_back(pMode1()); }

现在你得到一个警告 bool 不是 nullptr_t 并且你应该写

    if (!(pMode1() == nullptr) ) { modes->push_back(pMode1()); }

或者

    if (pMode1() != nullptr ) { modes->push_back(pMode1()); }

甚至

    if (pMode1()) { modes->push_back(pMode1()); }

其他注意事项

m_ChooseModeFromList 可能缺少循环。

重复使用相同代码但只有一个数字的差异告诉我它应该是某种数组,std::array 或 std::vector。

使用原始指针通常是错误的,但并非总是如此。

一个好的自助是使用调试器来单步调试代码。


推荐阅读