2011-08-20 5 views
-1

PHPの背景から来て、私はそれが面白い言語を見つけるので、私はC + +を学ぼうとしています。練習として、テンプレートを使用して単純なVectorクラスを作成したいと思います。これは難しくありません。しかし、私は1つの問題に遭遇します。私の基本的なベクトルクラスのテンプレートパラメータとして配列を使用する

私は、次のテンプレートクラス作成しました:

template <typename T> 
class Vector 
{ 
public: 
    Vector(int length); 
    ~Vector(void); 
    int getLength(); 

    T& operator[] (const int index); 

private: 
    T *_items; 
    int _count; 
}; 


template <typename T> 
Vector<T>::Vector(int length) 
{ 
    _items = new T[length]; 
    _count = length; 
} 

template <typename T> 
T& Vector<T>::operator[](const int index) 
{ 
    if (index >= getLength() || index < 0) 
     throw exception("Array out of bounds."); 
    return _items[index]; 
} 

すべての機能が実装されているが、しかし、彼らは私の質問に関連していないですので、私はそれらをここにコピーしていません。

このクラスは期待どおり動作しますが、例外は1つあります。 配列のベクトルを作成したい場合、それは動作しません。 例えば:私は何を明らかにしたいことは、ベクトルクラスの_itemsプロパティはint型になるということです

Vector<int[2]> someVector(5); 

[5] [2]。しかし、コンパイラは 'T'を 'int [2]'に置き換えるので、_itemsプロパティはint [2] [5](または少なくともデバッグから理解したものです。 )。その結果、[]演算子はもはや正しく動作しません。したがって、このクラス全体は配列にとって無用です。

この問題を解決する方法があるので、このクラスは配列に対しても機能しますか?それができない場合は、このクラスが配列で初期化されないようにする方法がありますか?

編集:これまでのすべてのご回答ありがとうございます。しかし、私は私の質問で完全にはっきりしていないかもしれません。まず第一に、私はこのクラスを作成してC++に慣れました。std :: vectorクラスがあることを知っています。また、ベクトルのベクトルを使用する方が良いことになりました。それは本当に問題ではありません。私はちょうどテンプレートをよく理解したいと思っています。一般的にC++なので、この種の問題に対処する方法を知りたいのです。私は、プログラムをクラッシュさせないクラスを作成できるようにしたい。私または他の誰かがこのクラスを今使っていて、このクラスのためにベクトルの代わりにプリミティブ配列を使用しようとすると、配列が間違っているためにプログラムがクラッシュすることがあります(Vector(y)はint [x] [y ]の代わりにint [y] [x]を使用します)。ですから正しい配列を作成するか、配列で配列を初期化するのを防ぐソリューションが必要です。

+4

[良いC++の入門書](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list)があることを確認してください。言語の基礎を理解することなく、良い、正しい、エラーのないC++コードを書くことを学ぶことは非常に難しくありません。 –

+1

"あまりにもハードではないテンプレートを使用する" - 独自のテンプレートクラス/関数を作成する場合は、 "テンプレート"と "それほど難しくない"は同じセンテンスには実際には収まりません。それはトリッキーです。 – Mat

+0

Matのコメントに追加するにはテンプレートは難しいかもしれません。特に、(int [2]オブジェクトのような)非基本的な型に対応したい場合には、テンプレートが難しいかもしれません。それらはC++を学ぶ素晴らしい方法ではありませんが、これは優れたSTL Vectorオブジェクトの存在から学ぶ大きな例ではありません。 – Pete855217

答えて

7

単純に、組み込みプリミティブ配列を使用しないでください。何でも。彼らはすごく吸う。 boost::arrayなどのクラスラッパーを使用してください。TR1またはC++ 0xがなく、両方ともarrayクラスを提供している場合は、必ずクラスラッパーを使用してください。 Vector<boost::array<int, 2>>は簡単にコンパイルされます。

なぜプリミティブ配列を使用しないのですか?

彼らはポインタへのひどい暗黙的な変換を持ち、帽子のドロップでそのサイズを忘れてしまったり、ファーストクラスの市民ではなく(例えばそれらに割り当てることはできません)、境界をチェックしません。 boost::array<int, 2>は、間違った変換を行わないプリミティブ配列であり、完全に汎用的です。たとえば、Vectorテンプレートは、boost::array<int, 2>でバットから正常に動作し、at()関数で境界チェックを行うことができます。

代わりに動的配列を使用することをお勧めしません。 boost::arrayは動的サイズの配列ではありません。これはポインタに変換されない固定サイズの値型配列であり、beginendsizeのような標準ライブラリで使用する関数を持っており、他の型とは違う扱いをすることができます。あなたが見つけたように12の特別ルール

+0

なぜプリミティブ配列を使用しないのですか?私は、Vectorクラスが過度に使用される状況が多く、特にコンパイル時に要素の数が分かっている場合は、プリミティブ配列で十分であると思います。しかし、経験が豊富だと思うので間違っているよりも間違っている可能性が高いので、なぜそれらを使用してはならないのか説明できますか? – Tiddo

+0

@Tiddo - 「決して」ではなく、「ほとんどありません」。その理由は、「彼らはすごく吸います」ということです。 C言語でビルドされた配列は、常に私たちを悩ましているハックです。彼らは彼らのサイズを忘れ、少し風でポインタに崩壊し、彼らはコンテナで動作しません。あるいは 'new'で。 –

+0

@Bo - さらに悪いことに、彼らのサイズはまったく分かりません。また、参考文献との唯一の違いは、デフォルトで値を渡すことです。私が間違っているなら、私を修正してください。 – Tiddo

0

のgetLength()があまりにも許可されたインデックス値ではありませんので、状態は、私はこれで間違っているいくつかのことを参照してください(最初の要素のインデックスは、最後のはgetLength()-1で、0ある)、

+1

いいですが、質問とは関係がないので、答えとして投稿してはいけません。 –

+0

これはおそらく彼の問題の原因です。 – hamstergene

+0

@Eugene:インデックス作成の計算がオフの場合、int配列ではなくint配列ではどうすれば動作するのですか? – Puppy

5

index >= getLength()を言わなければなりません。

  1. ジェネリックベクタークラスを作成する場合は、ベクトルのベクトルではなく配列のベクトルを扱うのはなぜですか?

ではなくint型のベクトルを定義する[2]、このようなものでサイズ2のベクトルのベクトルを作成してみてください:

Vector<Vector<int>> vector(5); 
for (int i = 0; i < 5; i++) 
{ 
    vector[i] = Vector<int>(2); 
} 
  1. よりもむしろ一定サイズのアレイを使用して、試してくださいポインタを使用します。

サイズ2の配列へのポインタを使用するのではなく、ポインタへのポインタを使用し、そのポインタに2つのスペースを割り当てます。ポインタは、配列全体をコピーするのではなく、単にポインタのアドレスを渡すことができるので、C++で処理する方がはるかに簡単です。一般的に、配列を渡すことは非常に悪いことです。

  1. ユーザーは長さを指定しない場合、それはゼロの大きさがデフォルトになりますように、あなたのコンストラクタ

よりもむしろVector(int length);でコンストラクタを宣言し、デフォルトのパラメータを追加し、Vector(int length = 0);を使用してみてください。

最後に、実際にはstd :: vectorがあることを知っていますか、これを知っていて、単にそれを複製しようとしていますか?テンプレートはC++の最も難しいテーマの1つであることが知られています。

+0

定数サイズの配列は、double Vectorよりもはるかに高速かつ安全であり、可能な限り使用する必要があります。 – Puppy

+0

私はオリジナルの記事では触れませんでしたが、配列のベクトルを使ってこれを修正する方法を知っています。しかし、私はこのクラスを作っていました。なぜなら、C++をよりよく理解したいからです。テンプレートの配列をどう扱うかを知りたいだけでした。私はstd :: vectorクラスを認識していますが、前に述べたように、私はこのクラスを練習としてのみ作成しました。私はポインタのアイデアが気に入っていますが、クラスをできるだけ悪用しても、アプリケーションをクラッシュさせないようにクラスを作成する必要があることをいつも学んできました。だから私はこのテンプレートの配列を禁止することができるようにしたい。それは可能ですか? – Tiddo

+0

特定の種類を禁止することはできません。あなたはstd :: vectorsでこの型を使用しようとしましたが、何が起こったのか見てきましたか? –

関連する問題