为何派生类使用using声明后未调用基类const赋值运算符?
CRTP场景下
operator=的调用异常分析 关于继承operator=的技术讨论中,普遍结论是基类的operator=会被派生类隐式定义的版本遮蔽,若需使用基类版本,可通过using Base::operator=声明引入。本文讨论CRTP(奇异递归模板模式)场景下的一个特殊问题:
#include <iostream> template <typename E> struct A { E& operator= (const E& other) { std::cout << "A<E>::op=\n"; return *(E*)this; } E& operator= (E& other) { std::cout << "A<E>::op no const=\n"; return *(E*)this; } }; struct B : public A<B> { using A<B>::operator=; }; int main () { B x, y; x = y; const B z; x = z; }
在main函数中,x = y会按预期调用E=B时的E& A<E>::operator=(E& other),但x = z却未调用E& A<E>::operator=(const E& other),这一行为的原因是什么?(注:此问题仅关注行为本身,不讨论代码风格)
原因解析
核心问题在于派生类B会被编译器隐式生成一个拷贝赋值运算符,这个隐式版本的签名是B& operator=(const B&),它在重载决议中的优先级高于通过using引入的基类版本:
- 隐式生成的拷贝赋值运算符:当派生类未显式定义拷贝赋值运算符时,编译器会自动生成一个,用于处理同类型const对象的赋值操作。
- 重载决议的优先级规则:在候选函数匹配时,派生类自身的成员函数比基类的成员函数优先级更高。对于
x = z(x为B,z为const B),隐式生成的B& operator=(const B&)是精确匹配,而基类中引入的B& operator=(const B&)属于基类成员,因此会被优先选择。 - 非const赋值的匹配逻辑:对于
x = y(y为非constB),隐式生成的拷贝赋值运算符仅接受const B&参数,此时基类的B& operator=(B&)是更匹配的候选,因此被调用。
内容的提问来源于stack exchange,提问作者Michaël
相关产品推荐
相关产品推荐

