Home > OS >  Why operator= and copy constructor are treated differently in virtual inheritance?
Why operator= and copy constructor are treated differently in virtual inheritance?

Time:11-01

It seems that in virtual inheritance, operator= and copy constructor are treated differently. Consider the following code:

#include <iostream>
#include <ostream>

class A {
public:
    A(int x) : x(x) {
        std::cout << "A is initialized" << std::endl;
    }

    A(const A& rhs) {
        std::cout << "Copy constructor for A" << std::endl;
    }

    A& operator=(const A& rhs) {
        std::cout << "A::operator=()" << std::endl;
        return *this;
    }

    virtual void funcB() = 0;
    virtual void funcC() = 0;
    int x;
};

class B : virtual public A {
public:
    B(int x) {
        std::cout << "B is initialized" << std::endl;
    }
    B(const B& rhs) {
        std::cout << "Copy constructor for B" << std::endl;
    }
    B& operator=(const B& rhs) {
        std::cout << "B::operator=()" << std::endl;
        return *this;
    }

    void funcB() override {
        std::cout << "B" << std::endl;
    }
    void funcC() override = 0;
};

class C : public B {
public:
    C(int x) : A(x   1), B(x) {
        std::cout << "C is initialized" << std::endl;
    }
    void funcC() override {
        std::cout << "C" << std::endl;
    }
};

int main() {
    C c(1);
    C c2(c);
    c2 = c;
    std::cout << c.x;
}

Here B inherit virtually from A and C inherit from B. The output is:

A is initialized
B is initialized
C is initialized
Copy constructor for A
Copy constructor for B
B::operator=()
2

We can see that the default copy constructor of C has successfully called the copy constructor for both B and A, which is what I want. But the default operator= did not call operator= of A, which is strange.

A possible explanation to this is that the copy constructor of A is called by B, not C. However, since I have deliberately made B pure virtual, I don't have to initialize A in the copy constructor of B and in fact I did not. So the copy constructor of A is called most likely from C, but I have no proof of it since A will be initialized before B anyway, no matter who calls its constructor.

CodePudding user response:

you're using compiler generated operator= (i.e C::operator=(const C&)), which calls operator= for all it's direct base class (and members)

since A is not a direct base class of C, A::operator=(const A&) is not called.

B is expected to copy A if it want, unlike constructor, you can implement assignment for B that doesn't change it's A (or whatever you want)


on the other hand, if A is direct base class

class C : public B , virtual public A { ... }

then the compiler generated operator= would call A's assignment operator (and it's unspecific whether A is assigned multiple times)

CodePudding user response:

c2 = c; Here we call operator= but class C doesn't have it (it is not generating in your case) then we call from base class B which has and it happens because we can cast C to B. That is why you see this message B::operator=().

If we call operator= it doesn't mean that it will call all operator= from base classes. operator= is a method that doesn't have the same behavior as constructors or destructors. If you want to see copy for A class then add next:

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

If you don't explicitly call for A::operator= consequently it doesn't copy - the value x is always be same after initialization.

  • Related