0

私は継承の概念も C++ も初めてなので、私の問題は本当にばかげているかもしれません...

class A {
    public :
        A() {}
        A(string name) {name_ = name}

    private :
        string name_;
}

class B : public A {
    public :
        B() {}
        B(string name, int number) {
            name_ = name;
            number_ = number;
        }

    private :
        string name;
        int number;
}

class C {
    public :
        C() {}
        void addClass(int id, A* a) {
            map[id] = a;
        }

    private :
        Hash_Map<int, A*> map;
}

void main() {
    C* c = new C();
    for (int i = 0; i < 10; i++) {
        B* b = new B("randomName", 50);
        c->addClass(i, b); //1st problem
        delete b;            //2nd problem
    }

}

最初の問題:「c」の「マップ」は、クラス「B」の属性「番号」を保持するべきではありませんか? A* をパラメーターに入れたことはわかっていますが、A から派生したクラスが複数ある場合、どのようにすればよいでしょうか?

2 番目の問題:「b」を削除すると、「マップ」のすべての属性がランダムな値になるようです。問題は、「b」を新しいオブジェクトにコピーする必要があることだと思いますが、addClass() パラメーターとして「A*」がある場合、どうすればよいでしょうか? 私のポインタ b はその親クラスに変換されているようです

編集:忘れていたコードのいくつかを変更する必要がありました...

4

1 に答える 1

1

問題の束:

1) クラス宣言内に初期化メンバーはありません! (あなたの編集はこれを修正しました)

class B : public A {
public :
    B() : name("A"), number(0) {} // initialize in constructor. that's what they are for!

private :
    string name;
    int number;

}

(Aの宣言についても繰り返します)

2)A実際のオブジェクトではなく、(addClass の引数として渡された) へのポインターのコピーをマップに格納しています。したがって、マップは次のようになります: 100 -> へのポインターb

次に、 b が指すものをすべて削除します。今何が含まれていると思いmap[100]ますか?ゴミへのポインタ!そのため、ポインターを外部で削除しないでください。Cさんに任せましょう。

3)(私の以前の回答には明らかなエラーがあり、誰かがそれを投票しました。したがって、以前の部分を保持して間違いを指摘します)必要がない限り、ポインターを使用しないでください。手間を省いてください。ギターを弾きに行くか、ハーブ・サッターの記事を読んでください!

void main() {
   // don't use pointers and require that you delete them (unless you need to)
   B b; // default constructor is called automatically. it is destroyed for you, by the compiler
        // at the end of its scope (in this case, closing brace of main() )

   C c; 
   c.addClass(100, b);
}

Cも直しましょう。これらの厄介なポインターを取り除くことはできますか?

class C {
public :
    C() {}
    void addClass(const int id, const A a) { // use const, its a good habit!
        map[id] = a;
    }

private :
    Hash_Map<int id, A a> map;

}

さて、これの何が問題なのですか?余分なコピーだけではありません。addClass に引数として値を渡すbと、コンパイラはb` のデータ (およびオーバーライド) のA一部をコピーします!b! So, we lost

したがって、絶対にポインターを使用する必要があります (参照はスコープの終了時に削除されるため、危険です)。

重要なのは、C が削除を所有するようにすることです。

したがって、コードは次のようになります。

class C {
public :
    C() {}
    ~C() {
       for(pair<int, A*>& p : map) // C++11 syntax, yay!
          delete p.second; // here's where you clean up. not in main.

    }
    void addClass(const int id, const A* a) {
        map[id] = a;
    }

private :
    Hash_Map<int, A*> map;
}

void main() {
    B* b = new B(); // back to square 1!
    C c;
    c.addClass(100, &b);
} // no memory leaks

しかし、私はあなたが言う削除の世話をするのが嫌いです..恐れる必要はありません。shared_ptr があります!

#include <memory>
using namespace std;
typedef shared_ptr<A> Aptr;

class C {
public :
    C() {}
    ~C() {
        cout << "Drinking a beer coz i use shared_ptr";     
    }
    void addClass(const int id, Aptr& a) {
        map[id] = a;
    }

private :
    Hash_Map<int, Aptr> map;
}

void main() {
    Aptr b(new B());
    C c;
    c.addClass(100, b);
} // still no memory leaks

それが役立つことを願っています。

于 2013-10-17T03:24:48.440 に答える