43

在我刚刚进行的测试之前,我相信只有构造函数不会在 C++ 中继承。但显然,任务operator=并不太...

  1. 这是什么原因?
  2. 是否有任何解决方法来继承赋值运算符?
  3. operator+=, operator-=, ...也是如此吗?
  4. 所有其他函数(除了构造函数/操作符=)都继承了吗?

事实上,我在做一些 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>
{
};

有什么解决方案可以让它工作吗?

编辑:好的,我已经隔离了问题。为什么以下不起作用?如何解决问题?

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

3 回答 3

42

赋值运算符在技术上是继承的;但是,它总是被派生类的显式或隐式定义的赋值运算符隐藏(参见下面的注释)。

(13.5.3 赋值) 赋值运算符应该由一个只有一个参数的非静态成员函数来实现。因为operator=如果未由用户声明,则为类隐式声明复制赋值运算符,因此基类赋值运算符始终被派生类的复制赋值运算符隐藏。

您可以实现一个虚拟赋值运算符,它只是将调用转发到基类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);
    }
};
于 2012-08-17T16:52:48.597 回答
13

赋值运算符继承的,有点,但是......在任何给定的类中,如果您不提供复制赋值运算符,编译器会为您生成一个。这意味着您的派生类有效地具有赋值运算符:

Derived& operator=( Derived const& );

并且适用通常的隐藏规则;这隐藏了所有基类赋值运算符。(如果基类有一个带有此签名的赋值运算符,则派生类将正常继承它。)

于 2012-08-17T17:22:52.453 回答
8
  1. 您的赋值运算符在技术上是继承的,但随后它被派生类中的默认复制赋值运算符隐藏。然后,此默认复制分配尝试调用不存在的基类复制分配,因为您使用自己的分配隐藏了它。

  2. 解决这个问题的最明智的方法是不要以不明显的方式使用运算符重载(=例如,不意味着复制分配)。在这种情况下,不要使用operator=: 将其assign称为 or set,然后它将继承并且不会被子副本分配隐藏。

  3. 这些运算符是继承的,并且没有编译器版本,因此它们永远不会像operator=.

  4. 它实际上只是没有被继承的构造函数,我想不出任何其他编译器生成的函数可以像operator=.

于 2012-08-17T17:33:14.633 回答