web-dev-qa-db-ja.com

C ++の設計-要素タイプが異なるベクタークラス

関連するクラスのグループを設計しようとしています。例えば:

  • 1つのテーブルクラスは整数のベクトルを保持し、ベクトルから整数を返す関数を持っています
  • 別のテーブルクラスはdoubleのベクトルを保持し、ベクトルからdoubleを返す関数を持っています

理想的には、2つのクラスが同じポインタ型を共有し、同じインターフェイスを備えて、クライアントで構築および使用できるようにしたいと考えています。唯一の違いは、1つのクラスは整数を返し、もう1つのクラスは倍精度を返すことが期待されることです。

デザインパターンに関する本を何冊か読みましたが、継承と構成の違いを理解しています。私はまだクラスのデザインの初心者であり、私は何か明らかなことを逃したと思う。以下は私の質問です:

  1. 未定義のデータメンバーまたは関数メンバーを持つことは良い習慣ですか?以下のサンプルコーディング。子クラスは、基本クラスのデータおよび関数メンバーの一部のみを定義します。
  2. 理想的には、2つの子クラス間に共通のインターフェースが欲しいです。ただし、あるクラスのget_value1関数は整数を返すため、別のクラスのget_value2関数はdoubleを返すため、別の関数名を付ける必要があります。これは重要ではありませんが、回避できますか?
  3. 継承を避け、単純に2つの異なるクラスを作成する必要がありますか?特に、2つのクラスが同じユーザーインターフェイスを共有していない場合はどうでしょうか。

class Base_Table
{
    std::vector<int> vec_int_;
    std::vector<double> vec_dbl_;
    virtual int get_value1(int);
    virtual double get_value2(int i);
};

class Int_Table : public Base_Table
{
    std::vector<int> vec_int_;
    virtual int get_value1(int i) override
    {
        return vect_int_[i];
    }
 };

class Frac_Table : public Base_Table
{
    std::vector<double> vec_dbl_;
    virtual double get_value2(int i) override
    {
        return vect_int_[i];
    }
};
1
DavidY

テンプレートクラスを作成します。あなたのユースケースがテンプレートが作成された理由です。あなたの例では、これは非常に簡単です:

template <class T> 
class Table
{
    std::vector<T> vec;
    T get_value(int i) const { 
        return vec[i];
    }
}

しかし、なぜ次のようにoperator []を定義する代わりに「get_value」を使用するのですか。

    T operator[](int i) const {
         return vec[i];
    }
3
kevin cline

C++の設計-要素タイプが異なるベクタークラス

合計タイプまたは タグ付きユニオン が必要なようです。多分あなたは std::variant を使いたいでしょう。

ほとんどの containers は同種です。特に、 std::vector のすべてのコンポーネントは同じ型を持っています(そのため、厳密な質問では意味がありません)。しかし、そのタイプは、もちろんタグ付きユニオンである可能性があります。

タグ付きユニオンのベクトル(std::vector<std::variant<int,float>> ...など)と、タグ付きベクトルのユニオン(std::variant<std::vector<int>,std::vector<float>>など)のどちらが必要かは不明です。これらは異なります!

union を含む独自のクラスを作成することもできます(その上にタグ付きユニオンを実装します)。次に 5つのルール に従う必要があります。

placement new を使用して、メモリを自分で管理することもできます。

(あなたが本当にしたいことは実際には不明確です;preciselysome abstract data type を指定して理由を説明してください、例えば目的のクラス-そのパブリックメンバー関数-およびその動作)

intdoubleは異なり、どういうわけか互換性がないことに注意してください [〜#〜] pod [〜#〜] タイプ。それらは通常、異なるサイズ、異なる配置を持ち、異なる方法で処理されます(たとえば、異なる プロセッサレジスタ に配置されるため、 [〜#〜] abi [〜#〜] は、それらについて知っている)。したがって、intdoubleの間のキャストは通常​​、(マシンレベルで)変換が必要であり、「フリー」ではありません(少なくとも1つのマシン命令を受け取り、情報を失う可能性があります)。 intの配列とdouble...の配列と見なすと、バイトの整列されたシーケンスは異なる意味を持ちます。