以下C ++代码无法编译:
class BaseA {
protected:
BaseA &operator = (const BaseA &rhs);
};
template<typename T>
class BaseB {
public:
T &operator = (const T &rhs) {
return *static_cast<T *>(this);
};
};
class Derived :
public BaseA,
public BaseB<Derived> {
};
int main() {
Derived foo;
Derived bar;
foo = bar;
return 0;
};
当我尝试编译时,我得到一个抱怨BaseA &BaseA::operator = (const BaseA &)
未定义。在stackoverflow上还有其他几个这样的问题,但它们似乎都与编译器自动生成调用Derived &Derived::operator = (const Derived &)
的{{1}}函数有关。在这种情况下,虽然BaseA::operator = (const BaseA&)
应该已经继承了Derived
中具有该确切签名的函数。如果我按照其他问题的建议并将BaseB<Derived>
添加到using BaseB<Derived>::operator =;
,则编译器会抱怨Derived
无法重载。
类是否无法继承此运算符?
编辑:要清楚,我很困惑为什么编译器在Derived &operator = (const Derived &)
已经从{{1}继承Derived
时给予Derived &operator = (const Derived &)
默认值T &operator (const T &) where [T = Derived]
}}。我可以理解为什么通常会创建默认的复制赋值运算符并覆盖任何继承的赋值运算符,但在这种情况下Base<Derived>
继承了一个运算符,其与其复制赋值运算符完全相同的签名。有没有办法编写Derived
以便其子类使用此运算符?
答案 0 :(得分:5)
不,赋值运算符operator=
不会被继承。
您没有默认
Derived& operator=(const BaseA& a);
但是,创建了默认赋值运算符:
Derived& operator=(const Derived& a);
,这将从BaseA
调用赋值运算符。所以这不是继承赋值运算符的问题,而是通过派生类中的默认生成运算符调用它。
还有一些说明:
标准说(12.8):
赋值运算符应由非静态成员实现 只有一个参数的函数。因为副本分配 如果未声明,则为类隐式声明operator operator = 用户(12.8),始终隐藏基类赋值运算符 由派生类的复制赋值运算符。
然后赋值运算符派生调用你的基础
非联合的隐式定义的复制/移动赋值运算符 class X执行其子对象的成员复制/移动分配。 首先按照它们的顺序分配X的直接基类 base-specifier-list中的声明,然后是immediate X的非静态数据成员按它们的顺序分配 在班级定义中宣布。
答案 1 :(得分:1)
赋值运算符是特殊成员函数之一。如果您不自己提供,编译器将通过分配基础然后分配成员为您生成一个。如果任何基数没有赋值运算符,则会生成一个。
您的问题是您已为BaseA
声明了赋值运算符,但尚未提供定义。因为它已声明,编译器不会为您生成一个,但它会尝试调用它来复制BaseA
子对象。然后链接器将无法找到定义。
请注意,对于赋值的具体情况,继承基本实现并没有多大意义。如果使用了它,只要一个基数具有赋值运算符,该对象的其余部分就不会被分配。在大多数情况下,操作的语义将被打破。
答案 2 :(得分:0)
你可以继承基类运算符和所有其他方法,如果你没有在基类中声明它 - 默认赋值运算符将由编译器生成,如果你声明它 - 当你必须提供自己的实现时,所以你是由于operator =而导致的错误未在您的BaseA类中定义,仅被声明。