Search code examples
c++polymorphismoperator-overloadingassignment-operatoroverload-resolution

How to make operator= accept derivatives of parameter like operator+?


I don't understand why a = b doesn't print out value from operator= 5 like operator+ (which seems to allows derivatives). Why does it do this instead of allowing derivatives and how can I make it accept derivatives too?

#include <iostream>

class A {
public:
    int value = 5;
};

class B : public A {
public:
    void operator=(const A& rhs) {
        std::cout << "value from operator= " << rhs.value << std::endl;
    }
    
    void operator+(const A& rhs) {
        std::cout << "value from operator+ " << rhs.value << std::endl;
    }
};

int main() {
    
    B a;
    B b;
    A c;
    
    std::cout << "testing operator=" << std::endl;
    std::cout << "testing with B:" << std::endl;
    a = b; // doesn't print anything
    std::cout << "testing with A:" << std::endl;
    a = c; // outputs: value from operator= 5
    
    std::cout << std::endl;
    
    std::cout << "testing operator+" << std::endl;
    std::cout << "testing with B:" << std::endl;
    a + b; // outputs: value from operator+ 5
    std::cout << "testing with A:" << std::endl;
    a + c; // outputs: value from operator+ 5
    
}

Solution

  • B::operator=(const A& rhs) is not a copy assignment or move assignment operator, so the implicitly-defined copy assignment operator still exists, and has the signature

    B& operator=(const B&);
    

    When doing a = b, this operator wins in overload resolution against yours because to call it, no derived-to-base conversion B -> A is necessary, unlike for your assignment operator.

    One way to have both Bs and As use this operator is:

    B& operator=(const A& rhs) {
        std::cout << "value from operator= " << rhs.value << std::endl;
        return *this;
    }
    
    B& operator=(const B& rhs) {
        return static_cast<A&>(*this) = rhs;
    }
    

    More traditionally, A should have its own user-defined copy assignment operator and B would forward to it through return A::operator=(rhs);