6

基本クラスに純粋な仮想代入演算子がある場合、その演算子を派生クラスに実装すると、基本クラスでリンカー エラーが発生するのはなぜですか?

現在、 http://support.microsoft.com/kb/130486に次の説明しかありません。通常の継承規則が適用されないため、動作は設計によるものであるとのことです。

私には明確ではありませんが、設計によりリンカーエラーが生成されるのはなぜですか? 誰かがこれについてもっと明確な説明をくれますか?

編集:エラーが発生した簡略化されたコードを追加しました:

class __declspec(dllexport) BaseClass {
public:
    int memberA;
    virtual BaseClass& operator=(const BaseClass& rhs) = 0;
};

class __declspec(dllexport) DerivedClass : public BaseClass {
public:
    int memberB;
    DerivedClass():memberB(0) {}
    virtual BaseClass& operator=(const BaseClass& rhs) {
        this->memberA = rhs.memberA;
        this->memberB = 1;
        return *this;
    }
};

int main(void)
{
    DerivedClass d1;
    DerivedClass d2;

    BaseClass* bd1 = &d1;
    BaseClass* bd2 = &d2;

    *bd1 = *bd2;
}

コードは、基本クラスでの純粋な仮想 operator= 宣言の有無にかかわらず、エラーなし でコンパイルされます。__declspec(dllexport)

__declspec(dllexport)の割り当て後、d1:: memberB*bd1 = *bd2;は 1 ですが、__declspec(dllexport)d1::memberB がある場合は変更されません。

を使用し__declspec(dllexport)、pure virtual 宣言を使用しない場合、 の代入後*bd1 = *bd2;、d1::memberB は変更されません。

4

3 に答える 3

7

標準のセクション12.8から:

13 クラス X の暗黙的に定義されたコピー代入演算子は、そのサブオブジェクトのメンバーごとの代入を実行します。base-specifier-list での宣言の順序で、X の直接基底クラスが最初に割り当てられ、次にクラス定義で宣言された順序で、X の直接の非静的データ メンバーが割り当てられます。 . 各サブオブジェクトは、そのタイプに適した方法で割り当てられます。

— サブオブジェクトがクラス型の場合、クラスのコピー代入演算子が使用されます (明示的な修飾によるかのように。つまり、より派生したクラスで可能な仮想オーバーライド関数は無視されます)。

サブクラスは暗黙的に定義されたコピー代入演算子を使用しており、基本クラスのコピー代入演算子の定義はありませんが、宣言されているため、コンパイル エラーではなくリンク エラーが発生します。

于 2010-09-21T14:09:48.610 に答える
7

operator= は継承されません。あなたのコードは C++ では無意味なので、コンパイラは自由にエラーを出すことができます。

あなたが指摘したKB記事から:http://support.microsoft.com/kb/130486

operator= は継承されないため、基本クラスでの operator= の宣言は使用されず、不要です。基本クラスで operator= を宣言しないでください。

これはおそらくコンパイル方法の副作用であり、バグとは見なしていないことを知らせているだけなので、修正する必要はありません。「設計上」とは必ずしも、このリンカ エラーがこの状況で表示する適切なエラー メッセージであると明確に判断したことを意味するわけではありません。コードが間違っているため、エラーが発生します。終わり。

于 2010-09-21T14:04:35.080 に答える
2

サンプルコードでは:

class A
{
public :
   // To workaround LNK2001, comment the following line.
   virtual const A& operator=( const A& f ) = 0;
};

class B : public A
{
public :
   const A& operator=( const A& g ) {return g;}
};

B aB1, aB2;

int /*void*/ main( void )
{
   aB2 = aB1;
}

aB2 = aB1は を呼び出しませんがconst A& B::operator=(const A&)、代わりに自動的に提供された を呼び出しますB& operator=(const B&);。これは、代入演算子を使用してクラスの基本部分を割り当てます。しかし、リンクに関しては、それが実装されていないことが判明しました。

于 2010-09-21T14:09:04.917 に答える