0

次のようなクラス階層があります。

class base
{
};

class derived1 : protected base
{
private:
    float m_price;
    int m_quantity;
    float m_value;
public:
//  float calculateValue();
};

class derived2 : protected base
{
private:
    double m_price;
    long m_quantity;
    double m_value;
public:
//  double calculateValue();
};

ここで、価格と数量を乗算して値を計算する関数を作成する必要があります。その目的は、将来的に新しいクラスを追加することをできるだけ簡単にすることです。お気づきかもしれませんが、これらのフィールドのデータ型はクラスによって異なるため、これは単純ではありません。実際には、概念的には同じことを行うこれらの関数がありますが、プログラミング用語では、これらは異なる操作です。

必要なカット アンド ペーストの量を最小限に抑えるために、これまでに考えられる解決策は、テンプレート関数を使用することです。

template <class A, B, C>
A calculate_value(B price, C quantity)
{
    A result;
    // Some code to do the multiplication, not sure if template specialisation is needed
    return result;
};

class derived1 : protected base
{
private:
    float m_price;
    int m_quantity;
    float m_value;
public:
    float calculateValue()
    {
       calculate_value < float, float, int > (m_price, m_quantity);
    }
};

これで問題なく機能しますが、これは、各クラスですべてのメンバー関数を定義する必要があることを意味します。たとえば、getValue という関数が必要な場合は、これらのテンプレート関数がさらにたくさん必要になります。

クラス メンバーのデータ型は、クラスが定義された時点で既知であるため、それらを関数定義に再び配置する必要があるのは重複しているように見えます。関数定義でこのすべてのテンプレート ビジネスを回避する方法はありますか?

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

アンディ

PS 次の質問を見たことがありますが、その質問の問題は少し異なります: データに応じて異なるデータ型を返す (C++)

4

5 に答える 5

6

異なる型を返す関数を持つ複数の派生クラスを持つという考えが好きだとは言えませんが、これを行う方法があります。

template
class base<typename value_type>
{
public:
    value_type calculateValue();
};
class derived1 : protected base<float>
{
private:
    float m_price;
    int m_quantity;
    float m_value;
};
class derived2 : protected base<double>
{
private:
    double m_price;
    long m_quantity;
    double m_value;
};

これにより、派生クラスで value_type を変更できますが、すべての共通関数をベースで宣言できます (そうする必要があります)。これは、マップなどの STL で使用されるアプローチに似ています。

于 2009-06-11T15:01:15.350 に答える
1

Curiously Recurring Template Pattern (CRTP) を使用します。

template <typename DERIVED>
class base {
protected:
    typename DERIVED::value_type calculateValue() {
        DERIVED *self = static_cast<DERIVED *>(this);
        return self->m_price * self->m_quantity;
    }
};

class derived1 : protected base<derived1> {
public:
    typedef float value_type;
    float m_price;
    int m_quantity;
};

class derived2 : protected base<derived2> {
public:
    typedef double value_type;
    double m_price;
    long m_quantity;
};

基本クラスがそれらにアクセスできるようにするために、makem_priceとpublic を行う必要があることに注意してください。m_quantityあなたはおそらくそれをしたくないので、代わりにパブリックアクセサーを追加するか(または、存在する場合はすでに存在するものを使用する)、またはそれらを基本クラスの保護されたメンバーにする必要があります(typedefsによって指定された型の)派生クラスで)、または派生クラスで基本クラスをフレンドとして宣言します。

パブリックgetValueメンバー関数が必要な場合は、それを基本クラスに追加して、継承をパブリックにすることができます。

于 2009-06-11T15:25:02.360 に答える
0

あなたができること:

レンプレート
クラスベース
{{
公衆:
    voidcalculateValue(value_type&x);
};
クラス派生1:保護されたベース
{{
プライベート:
    float m_price;
    int m_quantity;
    float m_value;
};
クラスderived2:保護されたベース
{{
プライベート:
    ダブルm_price;
    長いm_quantity;
    double m_value;
};
于 2009-06-11T17:57:09.407 に答える
0

このようなことはありますか?

template <typename A,typename B,typename C>
class base{
protected:
    A m_price;
    B m_quantity;
    C m_value;
public:
    C calculateValue(){
        m_value = m_quantity * m_price;
        return m_value;
    }
};

class derived1 : public base<int,float,int>{
};

class derived2 : public base<long,double,long>{
};
于 2009-06-11T15:01:54.320 に答える
0

オブジェクト指向の解決策は、戻り型のクラスを作成することです。その後、この戻り値の型を特殊な戻り値の型にサブクラス化できます。

いずれにせよ、お金のために浮動小数点演算を使用すると、問題が発生します。

于 2009-06-11T15:00:20.780 に答える