0

私はC++プログラミングに不慣れで、使用方法に応じて、設定したchar*変数から奇妙な値が返されます。私は明らかに本当に愚かなことをしていますが、問題はわかりません。次の数段落では、セットアップについて(ひどく)説明していますが、出力とコードを確認する方がおそらく簡単です。

基本的に、私にはいくつかのクラスがあります-MenuとMenuItem。MenuItemクラスの名前は、char*型です。メニュー項目の使用方法によっては、MenuItemsでgetName()を実行すると奇妙な結果が得られます。

状態(TestState)を持つMachineクラスがあります。このTestStateは、MenuItemsを含むメニューを作成します。メイン関数でTestStateを作成し、メニューを出力させると、期待どおりの結果が得られます。TestStateを含むマシンを作成し、メニューを印刷するように要求すると、メニューのルート項目の名前に奇妙なものが印刷されます。

出力-menuItem1を期待している最後の行ですが、 Hâ∆Hã=òを取得します

Output direct from TestState Object

Displaying menu state 
menuItem1
root not null 
menuItem1


Output from TestState within Machine

Displaying menu state 
menuItem1
root not null 
Hâ∆Hã=ò

これが私のコードです-Main.cpp

#include "Menu.h"
#include "Machine.h"
#include <iostream>

using namespace std;

Machine m;
TestState t;

int main(void) {
    cout << "Output direct from TestState Object" << endl << endl;
    t = TestState();
    t.print();


    cout << endl << endl << "Output from TestState within Machine" << endl << endl;
    m = Machine();
    m.printCurrentState();
}

Menu.h

#ifndef Menu_h
#define Menu_h

#include <stdlib.h>

class MenuItem {
public:
    MenuItem();
    MenuItem(const char* itemName);
    const char* getName() const ;

protected:
    MenuItem *next;
    const char* name;
};

class Menu {
public:
    Menu(MenuItem *rootItem);
    Menu();
    void setRoot(MenuItem *r);
    MenuItem* getRoot() ;
protected:
    MenuItem *root;
};

#endif

Machine.h

#ifndef MACHINE_H_
#define MACHINE_H_

#include "Menu.h"

class TestState;
class Machine;

class TestState {
public:
    TestState();
    virtual ~TestState();
    void print();
protected:
    Machine* machine;
    MenuItem menuItem1;
    Menu menuMain;
};

class Machine {
public:
    Machine();
    void printCurrentState();
protected:
    TestState testState;
};

#endif /* MACHINE_H_ */

Machine.cpp

#include "Machine.h"
#include <iostream>
using namespace std;

TestState::TestState() {
    menuItem1 = MenuItem("menuItem1");
    menuMain = Menu(&menuItem1);
}

void TestState::print(){
    cout << "Displaying menu state " << endl;
    cout << menuItem1.getName() << endl;

    if (menuMain.getRoot() == NULL) {
        cout << "root is null" << endl;
    } else {
        cout << "root not null " << endl;
        cout << menuMain.getRoot()->getName() << endl;
    }
}

TestState::~TestState() {
    // TODO Auto-generated destructor stub
}

Machine::Machine() {
    testState = TestState();
}

void Machine::printCurrentState() {
    testState.print();
}

どんな助けでもいただければ幸いです。私は少し迷っています。ありがとうデイブ

4

4 に答える 4

4

何が起こっているのかはMenu.root、どこかの一時オブジェクトを指しているのではないかと思います。main関数でマシンのコピーを作成していることに気付くでしょう。

// in main():
m = Machine(); // makes a machine, then copies it

そのマシンには、TestStateがあり、これには:MainMenuへのポインタがあります。MenuItem

// in MenuItem class definition:
MenuItem *root;

そのポインタは、元のマシンのメンバーのアドレスに初期化されます。問題は、そのオブジェクトが短時間しか存在しないことです。コピーが完了するとオブジェクトが破棄され、ダングリングポインタが残ります。

つまり、ポインタを含むオブジェクトをコピーするときは、古いオブジェクトではなく、複製されたオブジェクトのアドレスを反映するようにそれらのポインタを更新する必要があります。

次のようなコピーコンストラクタを追加する必要があります。

Machine::Machine(const Machine& other)
{
    teststate = other.teststate;
    teststate.machine = this; // you will need to expose TestState.machine to Machine
}

TestState::TestState(const TestState& other)
{
    machine = other.machine; // Machine copy constructor modifies this for us

    menuItem1 = other.menuItem1; // these 3 we have to do
    menuItem2 = other.menuItem2;
    menuMain = other.menuMain;

    menuMain.setRoot(&menuItem1); // update pointers to be to persistent copies
    menuItem1.setNext(&menuItem2);
    menuItem2.setNext(NULL);
}

システムがかなり壊れやすいことに気付くかもしれません。ドラゴンはその道を進んでいるので、オブジェクト間のポインターに頼ることはあまりお勧めしません。

于 2012-09-07T22:41:15.810 に答える
1

Thing name = Thing(ctorParams);名前をポインタにする代わりに、を使用しますnew Thing(ctorParams);。ポインタを使用していると思っていたようですが、新しいキーワードがなくても機能するため、先に進んで使用しなかったため、バグが発生しました。

于 2012-09-07T22:57:46.853 に答える
1
TestState::TestState() {
    menuItem1 = MenuItem("menuItem1");
    menuItem2 = MenuItem("menuItem2");
    menuMain = Menu(&menuItem1);
    menuMain.add(&menuItem2);
}

Machine::Machine() {
    testState = TestState();
}

Machineコンストラクターは一時的なものをTestState作成し、そのデータメンバーをにコピーしますMachine::testStateMachineコンストラクターが完了すると、一時はTestState消えますが、Machine::testState.menuMain.rootそれでも一時のメンバーを指します。

直し方:

変数を初期化するために存在するさまざまな方法のそれぞれが何を意味するのか、およびコンストラクターで初期化リストを使用する方法を学びます。

于 2012-09-07T22:44:14.550 に答える
0

Machineにはコピーコンストラクタがないため、Machine(具体的にはTestState)内のさまざまなポインタと参照がガベージを指しています。

于 2012-09-07T22:17:38.307 に答える