2017-07-06 90 views
3

我有點迷失在C++運營商。我想執行的賦值操作符的兩個不同的類,即這樣一個可以指定一個彼此:爲什麼我不能有一個純粹的虛擬賦值操作符?

class A { 
public: 
    virtual A &operator =(const A &a) = 0; 
}; 

class B : public A { 
public: 
    virtual A &operator =(const A &a) override { 
     std::cout << "B" << std::endl; 
     return *this; 
    } 
}; 

class C : public A { 
public: 
    virtual A &operator =(const A &a) override { 
     std::cout << "C" << std::endl; 
     return *this; 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    B b; 
    C c; 
    b = c; 

    // leads to a linker error: undefined reference to `A::operator=(A const&)' 
    //B b2; 
    //b = b2; 
} 

的第一項任務,似乎做的工作,「B」之稱。類似地,對於「c = b」,調用「C」。但是,當我取消註釋第二部分時,我收到鏈接器錯誤。如果我將A的運營商定義爲:

virtual A &operator =(const A &a) { 
     std::cout << "A" << std::endl; 
     return *this; 
} 

我得到「B」,「A」。咦?有人可以解釋爲什麼當分配兩個B時需要「A」,但是當B不是時B?

+0

你認識到,編譯器也爲B和C的一個默認的拷貝構造函數,以及默認NON VIRTUAL B ::運算符=(常數B&)和C ::運算(常量C&)操作符....創建虛擬(甚至非虛擬)賦值操作符從基到派生是要求麻煩的。 –

+0

這不是問題,但是你真的需要'std :: endl'做的額外的東西嗎? ''\ n''結束一行。 –

回答

2

編譯器會生成一個隱式複製分配操作符,該操作符在您執行B = B分配時正在選中。當您進行B = C分配時,不會選擇該選項。

http://en.cppreference.com/w/cpp/language/copy_assignment

https://wandbox.org/permlink/CM5tQU656rnwtrKl

如果你看看你的錯誤消息:

/tmp/cctHhd0D.o: In function `B::operator=(B const&)': 
prog.cc:(.text._ZN1BaSERKS_[_ZN1BaSERKS_]+0x1f): undefined reference to `A::operator=(A const&)' 
collect2: error: ld returned 1 exit status 

您可以看到鏈接錯誤是從裏B::operator=(B const&),其中,因爲你沒有一個定義,意味着它必須是自動生成的。

+0

因此,沒有任何直接的方法來迫使程序員爲給定類型提供賦值運算符?我猜連接器錯誤可能被稱爲強制執行,但我寧願一個編譯器錯誤。 –

+0

@MiroKropacek據我所知,沒有。複製分配操作符是特殊的。另外,請仔細考慮從基類到派生類是否有意義.. – xaxxon

+0

tbh,我也不覺得很舒服。它只是看起來更小的邪惡。對B中的'C'和C中的'B'進行單獨的運算符看起來更加陌生,更不用說強制執行了,把A作爲純粹的虛擬方法看起來並不正確。 –

2

當您指定b = b2;時,它會嘗試調用B的默認(隱式)分配。 默認分配將調用基類的默認分配,因此它最終將調用A::operator=(const A &a),這是純虛擬的。

所以你得到的鏈接錯誤。

1

根據派生類中基類的標準重寫虛擬賦值運算符不會阻止在您的情況下調用默認複製賦值運算符的生成。 B類的這個默認複製賦值操作符將直接調用A類的複製賦值操作符,因此您得到undefined reference錯誤。

13.5.3分配[over.ass]

2不限賦值操作,即使是複製和移動賦值運算符,可以是虛擬的。 [注意:對於已聲明瞭虛擬複製/移動分配的基類B的派生類D,D中的複製/移動賦值運算符不會覆蓋B的虛擬複製/移動賦值運算符。 [實施例:

struct B { 
    virtual int operator= (int); 
    virtual B& operator= (const B&); 
}; 

struct D : B { 
    virtual int operator= (int); 
    virtual D& operator= (const B&); 
}; 

D dobj1; 
D dobj2; 
B* bptr = &dobj1; 

void f() 
{ 
    bptr->operator=(99); // calls D::operator=(int) 
    *bptr = 99; // ditto 
    bptr->operator=(dobj2); // calls D::operator=(const B&) 
    *bptr = dobj2; // ditto 
    dobj1 = dobj2; // calls implicitly-declared D::operator=(const D&) 
} 
相關問題