メインコンテンツ

AUTOSAR C++14 Rule A10-3-5

A user-defined assignment operator shall not be virtual

説明

ルール定義

ユーザー定義の代入演算子はバーチャルにしないものとします。

根拠

基底クラスで代入演算子を virtual として定義すると、それを派生クラスでオーバーライドすることになります。派生クラスで代入演算子をオーバーライドすると、未定義の動作やランタイム エラーにつながる可能性があります。バーチャル代入演算子が 2 つの派生クラスでオーバーライドされる次のコード スニペットを考えてみましょう。

class Base {public:
	virtual Base& operator=(Base const& oth) = 0;
	//...
};
class Derived public: Base{ public:
	Derived& operator=(Base const& oth) override{/*...*/}
	//...
};
class Derived2 public: Base{public:
	Derived2& operator=(Base const& oth) override{/*...*/}
	//...
};
main(){
	Derived d1; 
       Derived2 d2;
	d1 = d2;
}
Derived::operator=Derived2::operator=Base::operator= をオーバーライドするため、これらのパラメーター リストを同じにする必要があります。

  • Derived::operator= は、Base オブジェクトへの参照を入力として取得し、Derived への参照を返します。

  • Derived2::operator= は、Base オブジェクトへの参照を入力として取得し、Derived2 への参照を返します。

Derived::operator= は、Base クラス オブジェクトと Derived クラス オブジェクトの両方への参照を受け入れます。これは、派生クラスへの参照がそれらの基底クラスと型互換性があるためです。同様に、Derived2::operator= も、Base クラス オブジェクトと Derived2 クラス オブジェクトの両方への参照を受け入れます。d1=d2Derived オブジェクトを Derived2 オブジェクトに代入しても、コンパイル エラーは発生しません。オブジェクトの d1d2 は無関係です。このような無関係のオブジェクト間の代入操作、コピー操作、または移動操作は、未定義であり、ランタイム エラーにつながる可能性があります。

未定義の動作とランタイム エラーを回避するには、ユーザー定義の代入演算子を非バーチャルのままにします。このルールは以下の演算子に適用されます。

  • 代入

  • コピー代入と移動代入

  • すべての複合代入

Polyspace 実装

Polyspace® は、基底クラス内のすべてのバーチャル代入演算子の宣言にフラグを設定します。

トラブルシューティング

ルール違反が想定されるものの、Polyspace から報告されない場合は、コーディング規約違反が想定どおりに表示されない理由の診断を参照してください。

すべて展開する

この例は、Polyspace が virtual 代入演算子にどのようにフラグを設定するかを示します。

#include <cstdint>
class Base
{
  public:
    virtual Base& operator=(Base const& oth) = 0;   // Noncompliant
    virtual Base& operator+=(Base const& rhs) = 0; // Noncompliant
};
class Derived : public Base
{
  public:
    Derived& operator=(Base const& oth) override 
    {
      return *this;
    }
    Derived& operator+=(Base const& oth) override 
    {
      return *this;
    }
    Derived& operator-=(Derived const& oth) // Compliant
    {
      return *this;
    }
};
class Derived2 : public Base
{
  public:

    Derived2& operator=(Base const& oth) override    
    {
      return *this;
    }
    Derived2& operator+=(Base const& oth) override    
    {
      return *this;
    }
    Derived2& operator-=(Derived2 const& oth)   // Compliant
    {
      return *this;
    }
};
/*
*/
void Fn() noexcept
{
  Derived b;
  Derived2 c;
  b = c;  
  b += c; 
  c = b;  
  c += b; 
  // b -= c; // Compilation error
  // c -= b; // Compilation error

}

クラスの DerivedDerived2 は、Base から派生しています。Base クラスでは、代入演算子の Base::operator=Base::operator+= がバーチャルとして宣言されています。次のいずれもコンパイル エラーになりません。

  • Derived オブジェクト bDerived2 オブジェクト c に代入できます。逆も同じです。

  • Derived オブジェクト bDerived2 オブジェクト c に追加できます。結果を bc のどちらかに代入できます。

bc は無関係なオブジェクトのため、上記動作のすべてが未定義で、ランタイム エラーにつながる可能性があります。Base::operator=Base::operator+=virtual として宣言すると、最終的に未定義の動作につながります。Polyspace は、これらのバーチャル代入演算子にフラグを設定します。

Base::operator-= の宣言は非バーチャルです。b-=cc-=b などの操作は、コンパイル エラーになります。

チェック情報

グループ: 派生クラス
カテゴリ: Required、Automated

バージョン履歴

R2020a で導入