質問

私は自分自身にC ++を教えようとしていますが、従来の<!> quot;新しい言語<!> quot;私がいつも使ってきた演習は、バイナリツリーやリンクリストなどのデータ構造を実装することです。 Javaでは、これは比較的単純でした。インスタンス変数Object dataを保持するクラスNodeを定義して、リストまたはツリーのすべてのノードにあらゆる種類のオブジェクトを格納できるようにしました。 (後でジェネリックを使用してこれを変更する作業を行いました。それはこの質問の目的ではありません。)

<!> quot;任意のタイプのオブジェクトを保存する同様の慣用的なC ++の方法は見つかりません。<!> quot; Cでは、voidポインターを使用します。 C ++でも同じことが言えますが、std::stringのインスタンスを作成してリスト/ツリー(std::string&からvoid*への無効なキャストに関するもの)に保存しようとすると、問題が発生します。そのような方法はありますか? C ++にはJavaのオブジェクト(またはObjective-CのNSObject)と同等のものがありますか?

ボーナスの質問:そうでない場合、およびvoidポインターを使用し続ける必要がある場合、<!> quot; right <!> quotとは何ですか。 static_cast<char*>(str.c_str())を<=>に保存する方法?私は偶然<=>に出会ったが、それは私がやろうとしていることの一種の冗長に思える。より良い方法はありますか?

役に立ちましたか?

解決

C ++には、Javaとは異なり、すべてのオブジェクトが継承するベースオブジェクトがありません。あなたがやりたいことに対する通常のアプローチは、テンプレートを使用することです。標準C ++ライブラリのすべてのコンテナはこのアプローチを使用します。

Javaとは異なり、C ++は汎用性のあるコンテナを実装するためにポリモーフィズム/継承に依存しません。 Javaでは、すべてのオブジェクトはObjectを継承するため、MyContainerを受け取るコンテナに任意のクラスを挿入できます。ただし、C ++テンプレートは、使用する型ごとに異なるクラスを実際に生成するようコンパイラーに指示するコンパイル時の構成体です。たとえば、次の場合:

template <typename T>
class MyContainer { ... };

その後、std::stringオブジェクトを受け取るintと、<=> sを受け取る別のMyContainerを作成できます。

MyContainer<std::string> stringContainer;
stringContainer.insert("Blah");

MyContainer<int> intContainer;
intContainer.insert(3342);

他のヒント

boost :: anyクラスをご覧ください。タイプセーフであり、標準のコレクションに入れることができ、ライブラリとリンクする必要はありません。クラスはヘッダーファイルに実装されます。

次のようなコードを記述できます:

#include <list>
#include <boost/any.hpp>

typedef std::list<boost::any> collection_type;

void foo()
{
    collection_type coll;
    coll.push_back(boost::any(10));
    coll.push_back(boost::any("test"));
    coll.push_back(boost::any(1.1));
}

完全なドキュメントはこちら: http://www.boost .org / doc / libs / 1_40_0 / doc / html / any.html

探しているのはテンプレートです。これらを使用すると、任意のデータ型を使用できるクラスと関数を作成できます。

テンプレートは、これを行う静的な方法です。 JavaおよびC#ジェネリックのように動作しますが、100%静的です(コンパイル時間)。同じコンテナに異なるタイプのオブジェクトなどを保存する必要がない場合は、これを使用します(他の回答ではこれを非常によく説明しています)。

ただし、異なる種類のオブジェクトを同じコンテナーに保存する必要がある場合は、ポインターを基本クラスに保存することで動的に行うことができます。もちろん、独自のオブジェクト階層を定義する必要があります。そのような<!> quot; Object <!> quot;は存在しないためです。 C ++のクラス:

#include <list>

class Animal {
public:
   virtual ~Animal() {}
};

class Dog : public Animal {
public:
   virtual ~Dog() {}
};

class Cat : public Animal {
public:
   virtual ~Cat() {}
};

int main() {
    std::list<Animal*> l;
    l.push_back(new Dog);
    l.push_back(new Cat);

    for (std::list<Animal*>::iterator i = l.begin(); i!= l.end(); ++i)
        delete *i;

    l.clear();

    return 0;
}

スマートポインターは使いやすいです。 boost::smart_ptr

の例
std::list< boost::smart_ptr<Animal> > List;
List.push_back(boost::smart_ptr<Animal>(new Dog));
List.push_back(boost::smart_ptr<Animal>(new Cat));
List.clear(); // automatically call delete on each stored pointer

標準Cスタイルのキャストを使用して、void*string*にキャストできるはずです。参照は、使用時にポインターのように扱われるのではなく、通常のオブジェクトのように扱われることに注意してください。そのため、関数への参照によって値を渡す場合、そのアドレスを取得するためにまだ参照を解除する必要があります。

ただし、他の人が言ったように、これを行うより良い方法はテンプレートを使用することです

static_cast<char*>(str.c_str())

私には奇妙に見えます。 str.c_str()はCに似た文字列を取得しますが、タイプはconst char *で、char *に変換するには通常const_cast<char *>(str.c_str())を使用します。ただし、stringの内部に干渉することになるので、それは良いことではありません。警告が表示されていませんか?

static_cast<void *>(&str)を使用できるはずです。あなたが受け取ったエラーメッセージは、何か他のものが間違っていることを私に示唆しているので、コードを投稿できればそれを見ることができます。 (データ型std::string&は<=>への参照であり、1へのポインターではないため、エラーメッセージは正しいです。ポインターの代わりに参照を取得する方法はわかりません。)

そして、はい、これは冗長です。それが意図されています。通常、キャストはC ++プログラムでは悪臭と見なされ、Stroustrupはキャストを見つけやすくすることを望んでいました。他の回答で説明したように、任意の基本型のデータ構造を構築する正しい方法は、キャストとポインターではなくテンプレートを使用することです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top