Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't have I a pure virtual assignment operator?

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?

like image 992
Miro Kropacek Avatar asked Jul 06 '17 07:07

Miro Kropacek


People also ask

Can operator be pure virtual in C++?

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).

Should assignment operator be virtual?

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.

Can operator overloading virtual?

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.

What does a move assignment operator do?

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.


3 Answers

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.

like image 114
xaxxon Avatar answered Nov 14 '22 03:11

xaxxon


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.

like image 26
Mine Avatar answered Nov 14 '22 03:11

Mine


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&)
}
like image 42
user7860670 Avatar answered Nov 14 '22 02:11

user7860670