Подтвердить что ты не робот

Operator = и функции, не наследуемые в С++?

До теста, который я только что сделал, я полагал, что только конструкторы не были унаследованы на С++. Но, видимо, назначение operator= не слишком...

  • В чем причина этого?
  • Есть ли какое-либо обходное решение для наследования оператора присваивания?
  • Это также относится к operator+=, operator-=,...?
  • Все остальные функции (кроме конструкторов /operator =) унаследованы?

Фактически, я столкнулся с этой проблемой, поскольку я делал 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>
{
};

Есть ли какое-нибудь решение для работы?

EDIT: Хорошо, я выделил проблему. Почему следующее не работает? Как решить проблему?

#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;
}
4b9b3361

Ответ 1

Оператор присваивания технически унаследован; однако он всегда скрывается явно или неявно определенным оператором присваивания для производного класса (см. комментарии ниже).

(13.5.3 Назначение) Оператор присваивания должен выполняться посредством нестатическая функция-член с точно одним параметром. Потому что копия оператор присваивания operator= неявно объявляется для класса a, если не объявленный пользователем, оператор назначения базового класса всегда скрытый оператором присваивания копии производного класса.

Вы можете реализовать оператор фиктивного присваивания, который просто перенаправляет вызов базовому классу operator=, например:

// 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);
    }
};

Ответ 2

Оператор присваивания наследуется, вроде, но... В любой заданной class, если вы не предоставляете оператор присваивания копии, компилятор генерирует один для вас. Это означает, что ваши производные классы эффективно имеют оператор присваивания:

Derived& operator=( Derived const& );

И применяются обычные правила сокрытия; это скрывает весь базовый класс операторов присваивания. (Если базовый класс имел оператор присваивания с этой сигнатурой производный класс наследует ее как обычно.)

Ответ 3

  • Ваш оператор присваивания технически унаследован, но затем он скрыт оператором присваивания по умолчанию в производном классе. Это назначение копии по умолчанию затем пытается вызвать назначение копии базового класса, которого нет, поскольку вы спрятали его с помощью собственного назначения.

  • Самый безопасный способ разрешить это - не использовать перегрузку оператора неочевидными способами (= не означает, например, назначение копии). В этом случае не используйте operator=: назовите его что-то вроде assign или set, а затем он наследует и не скрывается при назначении дочерней копии.

  • Эти операторы наследуются и нет версий компилятора, поэтому они никогда не будут автоматически скрыты, как operator=.

  • На самом деле это только конструкторы, которые не наследуются, и я не могу думать о каких-либо других генерируемых компилятором функциях, которые могли бы скрыть что-то от родителя, как в operator=.