3

私はかなり複雑な構成をしています。私はまた、あまりにも長い間それを見つめていたことにかなり確信があり、それらすべての木々が私の森の視界を覆い隠しています. そのため、実際に関連するのはほんの一部に過ぎないと思いますが、構成の完全な複雑さを示します。

さて、私の言葉での構成:

  • 独自の基底クラスから派生したテンプレート化された基底クラスは、いくつかの演算子のオーバーロードを実装します。

  • テンプレート化された基本クラスからサブクラス化されたクラス (独自の名前をテンプレート パラメーターとして使用) は、すべてのオペレーターにアクセスできます。このコンストラクトは、この質問に従って、演算子が等しい型でのみ操作できることを保証します。

  • 単一の特定のサブクラスは、いくつかの特殊なバージョンの演算子を実装します。このクラスを呼び出しDerivedます。このサブクラスも名前付きコンストラクターを使用するため、そのメイン コンストラクターはprivateです。

  • 別の基本クラスは、キャスト演算子 todoubleおよび to を実装Derivedして、そのサブクラスを (暗黙的に)Derived型にキャストできるようにします。これらの基底クラスの 1 つを呼び出しますOtherDerived

  • のインスタンスはDerived、 の名前付きコンストラクタの 1 つを呼び出すか、または のようにDerivedパススルーによって構築できます。OtherDerivedDerived D = OtherDerived(5.0);

私の問題:

  1. 定義はの代わりにdoubleDerived D = OtherDerived(5.0) * 2.0;にキャストOtherDerived(5.0)するように見えるため、 による乗算は単に double の積であり、inの基本クラスの出力ではありません。Derived2.0operator*Derived

  2. テンプレート化された基本クラスの の定義はoperator*=、 への参照を返すことはできません*this。これは、 の型が で*thisあるBaseClass<T>のに対し、目的の参照の型が だけであるためT&です。

これらの問題をエレガントに解決するにはどうすればよいですか?

参照をまったく返さないことで簡単に回避できるため、2 番目の問題はマイナーだと考えています。とはいえ、あると良いですね。Derived D = OtherDerived(...) * 2.0しかし、私にとって最も重要なことは、人々が何かを書くことができるようにするにはどうすればよいかということです。

人々に書くことを要求する

  • Derived D = (Derived)OtherDerived(...) * 2.0;、 また
  • Derived D = OtherDerived(...) * Derived::someName(2.0);、 また
  • Derived D = OtherDerived(...).operator*(2.0);

などはかなり奇妙で不必要に思えます...

NB:できれば、operator double()利用可能なままです:)

MWE は次のとおりです。

#include <iostream>
#include <cmath>

class SuperBase
{
public:
    virtual ~SuperBase(){}
    SuperBase() : value(0.0) {}

protected:
    double value;
    SuperBase(double value) : value(value) {}
};

template <class T>
class Base : public SuperBase
{
public:
    virtual ~Base(){}
    Base() : SuperBase() {}

    T& operator*=(double F)       { value *= F; return *this; }
    T  operator* (double F) const { return T(value*F); }

    double operator*(const T& U) const {
        return value*U.value;
    }

protected:
    double value;
    Base(double value) : SuperBase(value) {}
};

class Derived final : public Base<Derived>
{
public:

    ~Derived(){}
    Derived() : Base<Derived>(){}

    static Derived someName(double value) {
        return Derived(value);
    }

    Derived operator*(const Derived& D) const {
        return Derived(value/D.value);
    }

private:
    Derived(double value) : Base<Derived>(value) {}
};




class OtherBase
{
public:
    virtual ~OtherBase(){}

    operator double () { return value; }
    operator Derived() { return Derived::someName(value); }

protected:
    double value;
};

class OtherDerived final : public OtherBase
{
public:
    ~OtherDerived(){}

    OtherDerived(double value){
        this->value = std::sqrt(value);
    }
};



int main(int argc, char *argv[])
{
    Derived a = OtherDerived(1.05);     // Compiles fine

    Derived b = OtherDerived(1.05);     // Compiles fine
    b *= 2.0;                           // Error: cannot cast Base<Derived>
                                        // to Derived

    Derived c = OtherDerived(1.05)*2.0; // Error: casts the
                                        // OtherDerived to double,
                                        // so Derived(double) gets
                                        // called, which is private

    return 0;
}
4

3 に答える 3

1

Derived::operator*を非表示にしBase::operator*ます。using Base::operator*クラスDerivedに挿入して、でoperator*(double)利用できるようにしてくださいDerived

于 2012-10-16T09:01:10.813 に答える
1

問題 #1 については、スタンドアロンの乗算演算子を実装できます。

Derived operator*(const OtherDerived& op1, double op2)
  {
  return (Derived)val1*Derived::someName(val2);
  }

さらに、両方の変換演算子は でOtherBaseある必要がありますconst

于 2012-10-16T09:03:53.947 に答える
1

あなたのコードのケース#2では、あなたの問題は、コンストラクターがプライベートであるときにクラスにオブジェクトを作成させmainたいという事実に起因しているようです...呼び出されるコンストラクタ。Base<Derived>DerivedBase<Derived>::operator*=DerivedBase<Derived>Derived

mainあなたのコードのケース #3では、への暗黙的なキャストを防ぐために、またはクラスに を定義operator*します。OtherBaseOtherDeriveddouble

于 2012-10-16T09:06:11.930 に答える