43

私が行ったばかりのテストまで、C++ではコンストラクターだけが継承されていないと信じていました。しかし、どうやら、割り当てoperator=もそうではありません...

  1. その理由は何ですか?
  2. 代入演算子を継承するための回避策はありますか?
  3. operator+=、、operator-=...の場合も同様ですか?
  4. 他のすべての関数(コンストラクター/演算子=を除く)は継承されますか?

実際、CRTPを実行しているときに、この問題が発生しました。

template<class Crtp> class Base
{
    inline Crtp& operator=(const Base<Crtp>& rhs) {/*SOMETHING*/; return static_cast<Crtp&>(*this);}
};

class Derived1 : public Base<Derived1>
{
};

class Derived2 : public Base<Derived2>
{
};

それを機能させるための解決策はありますか?

編集:OK、私は問題を切り分けました。なぜ以下が機能しないのですか?問題を解決する方法は?

#include <iostream>
#include <type_traits>

// Base class
template<template<typename, unsigned int> class CRTP, typename T, unsigned int N> class Base
{
    // Cast to base
    public:
        inline Base<CRTP, T, N>& operator()()
        {
            return *this;
        }

    // Operator =
    public:
        template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
        inline CRTP<T, N>& operator=(const T0& rhs)
        {
            for (unsigned int i = 0; i < N; ++i) {
                _data[i] = rhs;
            }
            return static_cast<CRTP<T, N>&>(*this);
        }

    // Data members
    protected:
        T _data[N];
};

// Derived class
template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
{
};

// Main
int main()
{
    Derived<double, 3> x;
    x() = 3; // <- This is OK
    x = 3;   // <- error: no match for 'operator=' in ' x=3 '
    return 0;
}
4

3 に答える 3

42

代入演算子は技術的に継承されます。ただし、派生クラスに対して明示的または暗黙的に定義された代入演算子によって常に非表示になります(以下のコメントを参照)。

(13.5.3代入)代入演算子は、パラメーターが1つだけの非静的メンバー関数によって実装されるものとします。コピー代入演算子operator=は、ユーザーによって宣言されていない場合、クラスに対して暗黙的に宣言されるため、基本クラス代入演算子は、派生クラスのコピー代入演算子によって常に非表示になります。

次のように、呼び出しを基本クラスに転送するだけのダミー代入演算子を実装できますoperator=

// Derived class
template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
{
public:
    template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
    inline Derived& operator=(const T0& rhs)
    {
        return Base<Derived, T, N>::operator=(rhs);
    }
};
于 2012-08-17T16:52:48.597 に答える
13

代入演算子継承されますが、...どのクラスでも、コピー代入演算子を指定しない場合、コンパイラーがコピー演算子を生成します。つまり、派生クラスには効果的に代入演算子があります。

Derived& operator=( Derived const& );

そして、通常の隠蔽ルールが適用されます。これにより、すべての基本クラス代入演算子が非表示になります。(基本クラスにこのシグニチャーを持つ代入演算子がある場合、派生クラスはそれを通常どおり継承します。)

于 2012-08-17T17:22:52.453 に答える
8
  1. 代入演算子は技術的に継承されますが、派生クラスのデフォルトのコピー代入演算子によって非表示になります。次に、このデフォルトのコピー割り当ては、独自の割り当てで非表示にしたために存在しない基本クラスのコピー割り当てを呼び出そうとします。

  2. これを解決する最も賢明な方法は、演算子のオーバーロードを自明でない方法で使用しないことです(=たとえば、コピーの割り当てを意味するわけではありません)。この場合、使用しないでください:またはのoperator=ような名前を付けると、子コピーの割り当てによって継承され、非表示になりません。assignset

  3. これらの演算子は継承され、コンパイラバージョンがないため、のように自動的に非表示になることはありませんoperator=

  4. 継承されないのは実際にはコンストラクターだけであり、のように親から何かを隠すことができる他のコンパイラー生成関数は考えられませんoperator=

于 2012-08-17T17:33:14.633 に答える