operator= and functions that are not inherited in C++?

29,932

Solution 1

The assignment operator is technically inherited; however, it is always hidden by an explicitly or implicitly defined assignment operator for the derived class (see comments below).

(13.5.3 Assignment) An assignment operator shall be implemented by a non-static member function with exactly one parameter. Because a copy assignment operator operator= is implicitly declared for a a class if not declared by the user, a base class assignment operator is always hidden by the copy assignment operator of the derived class.

You can implement a dummy assignment operator which simply forwards the call to the base class operator=, like this:

// Derived class
template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
{
public:
    template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
    inline Derived& operator=(const T0& rhs)
    {
        return Base<Derived, T, N>::operator=(rhs);
    }
};

Solution 2

The assignment operator is inherited, sort of, but... In any given class, if you do not provide a copy assignment operator, the compiler generates one for you. That means that your derived classes effectively have an assignment operator:

Derived& operator=( Derived const& );

And the usual hiding rules apply; this hides all of the base class assignment operators. (If the base class had an assignment operator with this signature, the derived class would inherit it normally.)

Solution 3

  1. Your assignment operator is technically inherited, but then it's hidden by the default copy assignment operator in the derived class. This default copy assignment then tries to call the base class's copy assignment which doesn't exist since you hid it with your own assignment.

  2. The sanest way to resolve this is to not use operator overloading in non-obvious ways (= not meaning copy assignment for example). In this case, don't use operator=: Call it something like assign or set and then it will inherit and not be hidden by the child copy assignment.

  3. These operators are inherited and there are no compiler versions so they will never be automatically hidden like operator=.

  4. It really is only constructors that aren't inherited, and I can't think of any other compiler-generated functions that could hide something from the parent as in operator=.

Share:
29,932

Related videos on Youtube

Vincent
Author by

Vincent

Researcher, astrophysicist, computer scientist, programming language expert, software architect and C++ standardization committee member. LinkedIn: https://www.linkedin.com/in/vincent-reverdy

Updated on July 09, 2022

Comments

  • Vincent
    Vincent almost 2 years

    Until a test I've just made, I believed that only Constructors were not inherited in C++. But apparently, the assignment operator= is not too...

    1. What is the reason of that ?
    2. Is there any workaround to inherit the assignment operator ?
    3. Is it also the case for operator+=, operator-=, ... ?
    4. Are all other functions (apart from constructors/operator=) inherited ?

    In fact, I encountered this problem as I was doing some CRTP :

    template<class Crtp> class Base
    {
        inline Crtp& operator=(const Base<Crtp>& rhs) {/*SOMETHING*/; return static_cast<Crtp&>(*this);}
    };
    
    class Derived1 : public Base<Derived1>
    {
    };
    
    class Derived2 : public Base<Derived2>
    {
    };
    

    Is there any solution to get that working ?

    EDIT : OK, I have isolated the problem. Why the following isn't working ? How to solve the problem ?

    #include <iostream>
    #include <type_traits>
    
    // Base class
    template<template<typename, unsigned int> class CRTP, typename T, unsigned int N> class Base
    {
        // Cast to base
        public:
            inline Base<CRTP, T, N>& operator()()
            {
                return *this;
            }
    
        // Operator =
        public:
            template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
            inline CRTP<T, N>& operator=(const T0& rhs)
            {
                for (unsigned int i = 0; i < N; ++i) {
                    _data[i] = rhs;
                }
                return static_cast<CRTP<T, N>&>(*this);
            }
    
        // Data members
        protected:
            T _data[N];
    };
    
    // Derived class
    template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
    {
    };
    
    // Main
    int main()
    {
        Derived<double, 3> x;
        x() = 3; // <- This is OK
        x = 3;   // <- error: no match for 'operator=' in ' x=3 '
        return 0;
    }
    
    • Ed Heal
      Ed Heal over 11 years
      It is worth a read of item 45 of Scott Myers book (effecive C++) and also to not that sometime = does not mean = but copy constructor.
    • Mr.Anubis
      Mr.Anubis over 11 years
      your Derived1 's compiler generated operator= shadows base class's operator=
    • Mike Seymour
      Mike Seymour over 11 years
      @eq-: yes it will
    • Mike Seymour
      Mike Seymour over 11 years
      What exactly do you mean by "working"? Do you mean you want the base class operator available to use to assign derived-class objects from base-class objects? Or something else? An example of what you're trying to assign, and how, would be useful.
    • Mr.Anubis
      Mr.Anubis over 11 years
      if you moto is to inherit base class's operator= then in derived class you could do using Base<Derived1>::operator=
    • ed9w2in6
      ed9w2in6 over 11 years
    • Qnan
      Qnan over 11 years
      @lzprgmr exact duplicate, I would say. And there's a very good explanation and a workaround there.
  • Vincent
    Vincent over 11 years
    Okay. But so I have a really weird behaviour in my program. I will isolate the problem and edit my post.
  • Mike Seymour
    Mike Seymour over 11 years
    While technically correct, the inherited operator is hidden by the one declared (implicitly or explicitly) in the derived class.
  • Mike Seymour
    Mike Seymour over 11 years
    @eq-: Your test calls the implicit Derived::operator=, which in turn calls Base::operator=. However, the base class version can't be used to assign a derived class object from a base class object, since it's hidden. Demonstration. I'm assuming that that's what the question is about, although it's currently a bit vague.
  • Vincent
    Vincent over 11 years
    @eq : what would be the syntax of this dummy operator assignment ?