0

I'm having an issue overriding an operator= overload. When I try to use the operator to copy one Derived object into another, it's completely avoiding the Derived override, and just calling the Base operator= :

class Base
{
    public:
        virtual Base* clone() const;
    protected:
        virtual void operator=(const Base& copyBase);
}
class Derived : public Base
{
    public:
        Derived* clone() const;
    private:
        void operator=(const Base& copyBase) override;
}

Derived* Derived::clone() const
{
    Derived* clone = new (std::nothrow) Derived();
    if(clone)
    {
        *clone = *this;    // <--- Base operator= get's called
    }
    return clone;
}

Derived::clone() is being correctly called, but instead of calling Derived::operator= it's jumping to Base::operator=, and I can't seem to figure out why. Is there something special about virtual operator= or am I doing something silly?

Zepee
  • 1,640
  • 3
  • 20
  • 40
  • 2
    Assignment operators are *not* inherited. – PaulMcKenzie Feb 17 '15 at 19:28
  • 1
    Why not `Derived* clone = new (std::nothrow) Derived(*this);` it is shorter and more efficient. – Slava Feb 17 '15 at 19:33
  • There is rarely a case where `operator=()` needs to be virtual. `operator=` should always be defined with parameters of self type. (Also, don't have it return `void`) – Chintan Feb 17 '15 at 19:33
  • I'd say there is rarely a case where *any* operator should be virtual. Operator overloading is all about the public interface of a class, and the public interface should be non-virtual. In C++, virtual functions should normally be private, and operator overloading makes little sense for private functions. – Christian Hackl Feb 17 '15 at 19:35
  • See http://stackoverflow.com/questions/28442064/c-best-way-to-clone-objects/ regarding best way to implement clone – Chintan Feb 17 '15 at 19:36
  • I recommend to *not* get into the `virtual assignment operator` business. You have a base class, if it has copying to do, then defined a standard (non-virtual) assignment operator and implement it. If the derived classes need to make copies, then declare their assignment operators, and have their implementation call the base class version before doing their custom assignments. Trying to be too cute with using `virtual assignment operators` is confusing and hard to maintain (and debug). – PaulMcKenzie Feb 17 '15 at 19:38
  • 1
    @PaulMcKenzie Assignment operators *are* inherited, but always hidden by implicitly declared assignment operators. – Brian Bi Feb 17 '15 at 19:38
  • 2
    @Brian Yes, thanks for clarifying that. Assignment operators from base classes are not called automatically by a user-defined assignment operator of a derived class. The derived class version must explicitly call the base class assignment operator. – PaulMcKenzie Feb 17 '15 at 19:44
  • Slava yes you're right, I completely oversaw that... @PaulMcKenzie how would you handle assigning to a Derived object through a Base pointer then? This is not an issue in this case, I'm just curious. Thanks for the replies everyone, think I got my head around it now :) – Zepee Feb 17 '15 at 19:53
  • @Zepee - One thing you have to do is call the base class `operator=` explicitly -- you can't forget to do that. After that, then things become murkier. Is the `Base` object really a `Derived` object being passed? Unless you use RTTI, you can't assume that the `Base` is a `Derived`. That's why it's better to just write the assignment operator using a reference to `Derived` as the parameter. – PaulMcKenzie Feb 17 '15 at 20:00
  • @PaulMcKenzie absolutely, and that's exactly what the operator= did, dynamic_casting the pointer to check if it was indeed a Derived object. What I was wondering is, without a virtual operator=, how would this be handled: Base* b=new Derived(); *b=otherDerived; at this point you'd end up with only a partial assignment, which you probably don't want? – Zepee Feb 17 '15 at 20:10

1 Answers1

3

What you're forgetting is that regardless of what you have written, you still get a derived-specific copy assignment operator provided by the compiler. Since it's a better match than the base-class version, the default one is called.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • Hmm, not sure. Depends on why he thinks `void Base::operator=(const Base& copyBase)` is being called. – Mooing Duck Feb 17 '15 at 19:35
  • 1
    @MooingDuck because it is called by implicitly generated `Derived & Derived::operator=( const Derived &copy );` which he does not see – Slava Feb 17 '15 at 19:40