Clang linker error when overloading abstract operator =

The VisualStudio 2013 compiler does the following code perfectly, but clang 5.0 and 6.2 give me a linker error:

#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; } 

Here's the output of the build log:

 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&) is defined in Base , which inherits Derived , and Derived , using Base::operator= , so it must be defined for Derived , and not overridden by the default assignment operator.

One of the solutions I found was to remove the IBase::operator= method, but this is not ideal, since it is a method that any inheriting class should implement.

Does anyone know what the difference is and how to fix it? I would like to keep the IBase::operator= method if possible.

+6
source share
1 answer

The problem is that using-declarations is not considered a user-declared assignment operator [namespace.udecl] :

4 - [...] If the assignment operator obtained from the base class to the scope of the derived class has a copy / move signature for the derived class (12.8), the use-declaration does not in itself suppress the implicit declaration of the assignment operator of the derived class [. ..]

(In any case, using Base::operator= provides you with an assignment operator with the parameter type Base const& , which is not one of the parameter types that qualifies as a copy assignment operator [class.copy] / 17 - T , T& , T const& , etc. d.)

Since Derived does not have a user-defined copy destination operator, it is generated automatically, which ends with a call to IDerived::operator= , which calls IBase::operator= . Note that automatically generated copy assignment operators invoke subobject assignment operations, ignoring virtual overrides:

Each subobject is assigned in a way corresponding to its type:

  • if the subobject is of class type, as if calling operator= with the subobject as an expression of the object and the corresponding subobject x as one argument of the function (as if by explicit qualification, is ignoring any possible virtual override functions in more derived classes); [...]

It would be correct to write:

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

Please note that MSVC 2015 rejects your code, but works with the above 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 &)" ( ??4IBase@ @ UAEAAV0@ABV0 @@Z) referenced in function "public: class IDerived & __thiscall IDerived::operator=(class IDerived const &)" ( ??4IDerived@ @ QAEAAV0@ABV0 @@Z) main.exe : fatal error LNK1120: 1 unresolved externals 
+5
source

All Articles