6

Der Visual Studio 2013 Compiler behandelt den folgenden Code ganz gut, aber klirren 5.0 und 6.2 gibt mir einen Linker-Fehler:Clang Linker-Fehler, wenn abstrakte Betreiber Überlastung =

#include <memory> 

using namespace::std; 

class IBase 
{ 
public: 
    virtual IBase& operator=(const IBase& other) = 0; 
}; 

class Base : virtual public IBase 
{ 
public: 
    Base& operator=(const IBase& other) override 
    { 
     const Base& b = dynamic_cast<const Base&>(other); 
     return *this = b; 
    } 

    virtual Base& operator=(const Base& other) 
    { 
     return *this; 
    } 
}; 

class IDerived : virtual public IBase 
{ 
}; 

class Derived : public IDerived, public Base 
{ 
public: 
    using Base::operator=; 

}; 

int main(int argc, const char * argv[]) { 
    shared_ptr<Derived> d1 = make_shared<Derived>(); 
    shared_ptr<Derived> d2 = make_shared<Derived>(); 
    *d2 = *d1; 
} 

Hier ist die Build-Log-Ausgabe:

Ld /Users/Jennifer/Library/Developer/Xcode/DerivedData/Operator-bjjgcoxcziyegjgmazknrandutqz/Build/Products/Debug/Oper normal x86_64 
    cd /Users/Jennifer/Documents/Operator 
    export MACOSX_DEPLOYMENT_TARGET=10.9 
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -L/Users/Jennifer/Library/Developer/Xcode/DerivedData/Operator-bjjgcoxcziyegjgmazknrandutqz/Build/Products/Debug -F/Users/Jennifer/Library/Developer/Xcode/DerivedData/Operator-bjjgcoxcziyegjgmazknrandutqz/Build/Products/Debug -filelist /Users/Jennifer/Library/Developer/Xcode/DerivedData/Operator-bjjgcoxcziyegjgmazknrandutqz/Build/Intermediates/Operator.build/Debug/Oper.build/Objects-normal/x86_64/Oper.LinkFileList -mmacosx-version-min=10.9 -stdlib=libc++ -Xlinker -dependency_info -Xlinker /Users/Jennifer/Library/Developer/Xcode/DerivedData/Operator-bjjgcoxcziyegjgmazknrandutqz/Build/Intermediates/Operator.build/Debug/Oper.build/Objects-normal/x86_64/Oper_dependency_info.dat -o /Users/Jennifer/Library/Developer/Xcode/DerivedData/Operator-bjjgcoxcziyegjgmazknrandutqz/Build/Products/Debug/Oper 

Undefined symbols for architecture x86_64: 
    "IBase::operator=(IBase const&)", referenced from: 
     IDerived::operator=(IDerived const&) in main.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

IBase::operator=(IBase const&) wird in Base welche Derived erbt von definierten und Derivedusing Base::operator= ist es so sollte fürdefiniert werden,, nicht vom Standardzuweisungsoperator überschrieben. Eine Lösung, die ich fand, war die IBase::operator= Methode zu entfernen, aber das ist nicht ideal, da es eine Methode ist, die jede erbende Klasse implementieren müsste.

Weiß jemand, was der Unterschied ist und wie man es beheben kann? Ich möchte die Methode IBase::operator= wenn möglich beibehalten.

Antwort

5

Das Problem ist, dass eine using-Deklaration nicht als Benutzer deklarierte Zuweisungsoperator zählt [namespace.udecl]:

4 - [...] If an assignment operator brought from a base class into a derived class scope has the signature of a copy/move assignment operator for the derived class (12.8), the using-declaration does not by itself suppress the implicit declaration of the derived class assignment operator [...]

(In jedem Fall using Base::operator= gibt Ihnen einen Zuweisungsoperator mit dem Parameter Typ Base const&, die [class.copy]/17 Qualifikation als Kopie Zuweisungsoperator nicht einer der Parametertypen ist - T, T&, T const&, etc.)

Da Derived keinen vom Benutzer deklarierten Kopierzuweisungsoperator hat, wird einer automatisch generiert, der den Aufruf IDerived::operator= aufruft, der IBase::operator= aufruft. Beachten Sie, dass automatisch generierte Kopie Zuweisungsoperator subobject Kopie Zuweisungsoperator ignorieren virtuelle Überschreibungen nennen:

Each subobject is assigned in the manner appropriate to its type:

  • if the subobject is of class type, as if by a call to operator= with the subobject as the object expression and the corresponding subobject of x as a single function argument (as if by explicit qualification; that is, ignoring any possible virtual overriding functions in more derived classes); [...]

Ein Update wäre zu schreiben:

Base& operator=(Derived const& other) { return Base::operator=(other); } 

Beachten Sie, dass MSVC 2015 Code ablehnt, sondern arbeitet mit der oben Fix:

main.cpp(36): warning C4250: 'Derived': inherits 'Base::Base::operator =' via dominance 
main.cpp(14): note: see declaration of 'Base::operator =' 
main.obj : error LNK2019: unresolved external symbol "public: virtual class IBase & __thiscall IBase::operator=(class IBase const &)" ([email protected]@[email protected]@@Z) referenced in function "public: class IDerived & __thiscall IDerived::operator=(class IDerived const &)" ([email protected]@[email protected]@@Z) 
main.exe : fatal error LNK1120: 1 unresolved externals 
+0

Bezüglich des ersten Absatzes in der Antwort, kann es sich lohnen, klarzustellen, dass selbst wenn die using-Deklaration eine Deklaration mit dem richtigen Parameter typ hat e, es würde die implizite Deklaration des Kopierzuweisungsoperators immer noch nicht unterdrücken. – bogdan

+0

@bogdan danke, ich habe diesen Teil vergessen. – ecatmur