Why are virtual assignment operators a can of worms?
Let us take the classic shape example:
class Shape
{
public: virtual bool operator==(const Shape & s) const = 0;
};
class Rectangle : public Shape
{
public: bool operator==(const Shape & s) const
{ /*...*/ }
};
class Circle : public Shape
{
public: bool operator==(const Shape & s) const
{ /*...*/ }
};
Now comes the fun part.
Rectangle r;
Circle c;
Shape * p_shape1 = &r; // This is legal.
Shape * p_shape2 = &c; // So is this.
// What happens here????
if (r == *p_shape2)
{
//...
}
IMHO, operators should not be inherited. There is no guarantee that Child1's operators will be passed Child1 instances; They could be passed Child` or Child3 or even GrandChild1 instances.
C++ virtual assignment operator
Your problem might be that you define the class in a namespace, but you define the operators outside that namespace without specifying it. Because of this, the compiler can't connect the definition to the declaration.
Ishamael pointed out that you don't specify what happens when a non-Point Shape is assigned to a Point. This is necessary for a virtual assignment operator; see his answer. But this virtual assignment operator could end up doing a lot of unexpected things, like cutting off parts of objects if the wrong types are assigned to each other.
You don't need the virtualness to ensure that the Shape operator also gets called when Point is assigned. Just call the Shape operator inside the Point operator. Making the operator virtual would actually have the opposite effect; the Point operator would override the Shape operator even if the instance you're calling it with is referred to as a Shape.
Point& Point::operator = (const Point& source) //assign
{
if (this == &source) //avoid self-assignment
return *this;
Shape::operator=(source); // also call the base class operator
m_x = source.m_x;
m_y = source.m_y;
return *this;
}
Pure virtual assignment operator in c++
Try it like this
#include <iostream>
#include <string>
using namespace std;
class Base {
public:
virtual ~Base() {}
};
class D1 : public Base {
public:
virtual ~D1() {}
//...some fields
//assignment operator, it does the deep copy of the members
D1& operator=(const D1&) {
cout << "D1:operator=(const D1&)\n";
return *this;
}
};
class D2 : public Base {
public:
virtual ~D2() {}
//...some fields
//assignment operator, it does the deep copy of the members
D2& operator=(const D2&) {
cout << "D2:operator=(const D2&)\n";
return *this;
}
};
main
D1 *d1 = new D1();
D1 *d1_another = new D1();
//this doesn't work:
*d1 = *d1_another;
D2 *d2 = new D2();
D2 *d2_another = new D2();
//this doesn't work:
*d2 = *d2_another;
Why can't have I a pure virtual assignment operator?
The compiler generates an implicit copy-assignment operator that is being selected when you do a B = B assignment. That is not selected when you do a B = C assignment.
http://en.cppreference.com/w/cpp/language/copy_assignment
https://wandbox.org/permlink/CM5tQU656rnwtrKl
If you look at your error message:
/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
You can see that the linker error is from inside B::operator=(B const&)
, which, since you didn't define one, means it must be auto-generated.
C++: pure virtual assignment operator
From section 12.8 of the standard:
13 The implicitly-defined copy assignment operator for class X performs memberwise assignment of its subobjects. The
direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate
non-static data members of X are assigned, in the order in which they were declared in the class definition. Each subobject
is assigned in the manner appropriate to its type:— if the subobject is of class type, the copy assignment operator for the class is used (as if by explicit qualification;
that is, ignoring any possible virtual overriding functions in more derived classes);
The subclass is using the implicitly-defined copy assignment operator, and there is no definition of the base class's copy assignment operator, but it is declared, so you get a link error instead of a compilation error.
Polymorphism with virtual assignment operator
I believe it is because virtual int operator=(A& rIn)
in class B is not the real default operator=
so the compiler is creating a B& operator=(const B& other)
for you and using that one.
To add to this, it is not enough to override your virtual operator=, you must also define the regular operator=.
And of course it is best to use C++11 features like the override
keyword to guarantee that you actually wrote the function signature you meant to, instead of creating a new virtual function.
Related Topics
When Should You Use Constexpr Capability in C++11
How to Reassign the Reference in C++
Propagating 'Typedef' from Based to Derived Class For 'Template'
What Exactly Is the "Immediate Context" Mentioned in the C++11 Standard For Which Sfinae Applies
Why Does C++ Compilation Take So Long
How to Efficiently Select a Standard Library Container in C++11
Determine the Line of Code That Causes a Segmentation Fault
When Should I Use Std::Thread::Detach
How to Convert a Lambda to an Std::Function Using Templates
How Does Generic Lambda Work in C++14
Why Is Std::Map Implemented as a Red-Black Tree
Running My Program Says "Bash: ./Program Permission Denied"
Detecting Superfluous #Includes in C/C++
How to Link Opencv in Qtcreator and Use Qt Library
What Requirements Must Std::Map Key Classes Meet to Be Valid Keys