I'm a bit lost in C++ operators. I'd like to enforce the assignment operator for two different classes, i.e. so one can assign one to each other:
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;
}
The first assignment seems to do the job, "B" is called. Similarly, for "c = b", "C" is called. However when I uncomment the second part, I get the linker error. If I define A's operator like:
virtual A &operator =(const A &a) {
std::cout << "A" << std::endl;
return *this;
}
I get "B", "A". Huh? Can somebody explain why "A" is needed when two B's are assigned but not when B <- C is?
For a first-time C++ question, you're hitting a lot of subtle issues, so gratz for that =P. This is a slightly tricky problem, because operator+ should return an object (not a reference), so it can't return an abstract class (which Figabs is here because it has a pure virtual function).
The assignment operator is not required to be made virtual. The discussion below is about operator= , but it also applies to any operator overloading that takes in the type in question, and any function that takes in the type in question.
If you want to override a virtual function in a child-class, then you need to declare the function override in the child class. So yes, the declaration is needed.
In the C++ programming language, the move assignment operator = is used for transferring a temporary object to an existing object. The move assignment operator, like most C++ operators, can be overloaded. Like the copy assignment operator it is a special member function.
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.
When you assign b = b2;
, it tries to call B's default (implicit) assignment.
And the default assignment will invoke base class's default assignment, so it will eventually call A::operator=(const A &a)
, which is pure virtual.
And so you get the link error.
According to standard overriding virtual assignment operator of base class in derived class does not prevent generation of default copy assignment operator which is being invoked in your case. This default copy assignment operator of class B
will directly call copy assignment operator of class A
hence you are getting undefined reference
error.
13.5.3 Assignment [over.ass]
2 Any assignment operator, even the copy and move assignment operators, can be virtual. [Note: For a derived class D with a base class B for which a virtual copy/move assignment has been declared, the copy/move assignment operator in D does not override B’s virtual copy/move assignment operator. [Example:
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&)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With