0

作成中のライブラリ用に独自のベクター クラスを「作成」しようとしています。ベクトル クラスを最初から作成するつもりはありませんがstd::vector、親クラスとして使用し、派生したベクトル クラスに何かを追加するだけです。

そうは言っても、ちょっとアドバイスが必要です。私の質問は次のとおりです。

vector1) 派生クラスを (もちろん、別の名前空間内で)呼び出すのは悪い考えですか? この場合、どのような競合が発生しますか?

2)数学演算子をオーバーロードして、ベクトルを追加したり、ベクトルを定数で乗算したりできるようにしたいstd::vector. ただし、数学演算子をstd::vector直接オーバーロードして、(さらに別の...) ベクトル クラスを作成する手間を省くことができますが、これは悪い考えですか?

3) からコンストラクターを継承したいのstd::vectorですが、コンパイラ エラーなしでこれを行うには多くの問題があります。誰かがこれをどのように行うことができるかを示す具体的な例を教えてください。

ありがとうございました!

4

3 に答える 3

3

私はあなたがそれをするのを思いとどまらせます. 新しいコンテナーが必要な場合は、コンテナーからパブリックに継承するのではなく、埋め込む (またはプライベートに継承する)だけです。std::vector<>

ご質問について:

1) 派生クラス ベクトル (もちろん、別の名前空間内) を呼び出すのは悪い考えですか? この場合、どのような競合が発生しますか?

あなたもあなたのクライアントも、ディレクティブstdを通じて名前空間とあなたの名前空間の両方をインポートしない限りusing、これに関して特に問題はないと思います。

2) 数学演算子をオーバーロードして、ベクトルを追加したり、ベクトルを定数で乗算したりできるようにしたいと考えています。これが、std::vector の上にベクトル クラスを構築することにした理由です。ただし、 std::vector の数学演算子を直接オーバーロードして、(さらに別の...) ベクトル クラスを作成する手間を省くことができますが、これは悪い考えですか?

はい、これは悪い考えです。の数学演算子のオーバーロードを作成した場合、 が属するstd::vector名前空間にそれらを作成できませんでした。std::vectorADL によって、operator +適切でない場合でも、その名前空間でグローバルが見つかる可能性があります。その場合、operator +検索すら行われず、コンパイラ エラーが発生します。

3) std::vector からコンストラクターを継承したいのですが、コンパイラ エラーなしでこれを行うには多くの問題があります。誰かがこれをどのように行うことができるかを示す具体的な例を教えてください。

C++11 では、継承されたコンストラクターを使用できました。例えば:

#include <vector>

template<typename T, typename Allocator = std::allocator<T>>
class myvector : public std::vector<T, Allocator>
{
    using typename std::vector<T, Allocator>::vector;
};

#include <iostream>

int main()
{
   std::vector<int> vi { 1, 2, 3, 4, 5};

   // Uses inherited constructor
   myvector<int> v(vi.begin(), vi.end());

   for (auto i : v) { std::cout << i << " "; };
}

これは、継承されたコンストラクターをサポートする GCC 4.8.0 (ベータ) で動作する実際のです。

于 2013-03-03T20:23:15.917 に答える
2

まず、必要に応じて継承を難読化できることに注意してください。private継承を使用してからvector、withusingステートメントですべての機能を使用できるようにします。たくさんあるので、入力するのはまだかなりの量ですが、vectorすべての関数を明示的に委譲するほどではなく、継承に対する通常の反対意見を防ぎます.派生クラスを誤ってスライスしたり、仮想デストラクタがない場合の型が間違っています。とにかく誰かが削除するべきではありませvectorん。

1)名前空間から同じ名前を使用することstdは本質的に問題ではありませんが(結局のところ、それが名前空間の目的です)、読者を混乱させることがあります。using std::vector;彼らはあなたがどこかでやったと思い込んでいるかもしれません。これは彼ら自身の責任ですが、別の適切な名前を思いつくことができれば、読者の間違いを罰しても何も得られません.

2) 標準クラスの演算子をオーバーロードできますが、std名前空間ではできません。これにより、どのスコープでそれらをオーバーロードする必要があるかという疑問が残ります。通常、ヘッダー ファイルのグローバル スコープに何かを入れたくはありませんが、たとえば、名前空間と呼ばれる名前空間にそれらをvector_arithmetic入れusing namespace vector_arithmetic;てから、それぞれのスコープに入れることができます。それらを使用したいです。できるからといって、それが賢明であるとは限りません。読者は、 のような一般的なクラスで使用できる演算子を知っていることを期待していvectorます。

3) C++11 コンストラクターの継承がない場合、コンストラクターを継承できません。代わりに、適切なパラメーターを受け取り、初期化子リストで適切な基本クラスのコンストラクターを呼び出す独自のコンストラクターを苦労して書き出す必要があります。標準 (またはその他のドキュメント) には、必要なすべてのコンストラクター シグネチャが記載されています。テンプレート化されたコンストラクターには特に注意してください。コンストラクターは C++03 と C++11 で同じではないことに注意してください。

最後に、いくつかのフリー関数を書くことを検討してください:

template <typename T>
T sequence_add(const T &lhs, const T &rhs) {
    if (rhs.size() != lhs.size()) throw std::logic_error("size mismatch");
    T result(lhs.size());
    std::transform(lhs.begin(), lhs.end(), rhs.begin(), result.begin(),
        std::plus<typename T::value_type>()
    );
    return result;
}

std::vector<int> i,j;
std::vector<int> k = sequence_add(i,j);

等々。演算子のオーバーロードが混乱を引き起こす場合は、一般的には価値がありません。

于 2013-03-04T00:29:44.743 に答える
1

1) 名前空間の下に独自のベクトルを記述します。ただし、STL から派生させないようにしてください。

2,3) を忘れstd::vectorて、独自のメソッドと演算子を作成します。

std::vectorまた、新しいクラスをラップして、それを操作するインターフェイスを作成することもできます。

于 2013-03-03T20:20:09.880 に答える