基于奇异递归模板模式(CRTP)的抽象基类赋值运算符实现问题
问题原因
你遇到的编译错误是两个核心原因共同导致的:
- 赋值运算符签名冲突
基类ArrayBase中定义的operator=参数为const t_derived_class&,对于StaticArray派生类来说,这个参数类型就是const StaticArray&,和C++为派生类隐式生成的默认拷贝赋值运算符签名完全一致。当你在派生类中用using Base::operator=导入基类的赋值运算符时,两个同签名的函数无法重载,编译器会直接将派生类的拷贝赋值运算符标记为删除。 - 基类引用成员的限制
基类ArrayBase包含引用类型成员Derived,C++规定包含引用成员的类会隐式删除默认拷贝赋值运算符,即使没有签名冲突,默认的赋值逻辑也不符合预期——Derived引用永远应该指向当前派生类实例本身,赋值操作不应该修改它的指向。
修复方案
方案1:抽取公共赋值逻辑(推荐,兼容性最好)
将基类的赋值逻辑抽为普通成员函数,派生类显式实现拷贝赋值运算符调用该逻辑,完全避免签名冲突:
第一步:修改ArrayBase基类
template <class t_derived_class, class data_type> class ArrayBase { private: t_derived_class& Derived; // 抽取公共赋值逻辑为protected成员,供派生类调用 protected: void assign(const t_derived_class& _other_derived) { for(std::size_t i = 0; i < Derived.size(); ++i) { Derived[i] = _other_derived[i]; } } public: /** Default constructor. */ ArrayBase() : Derived(static_cast<t_derived_class&>(*this)) {} /** Pure virtual desctructor. */ virtual ~ArrayBase() {}; // 删除基类默认拷贝赋值,避免不必要的隐式操作 ArrayBase& operator=(const ArrayBase&) = delete; /** Index operator overloads. */ data_type& operator[](const std::size_t _index) { return *(Derived.begin() + _index); } const data_type& operator[](const std::size_t _index) const { return *(Derived.begin() + _index); } };
第二步:修改StaticArray派生类
显式实现拷贝赋值运算符,调用基类的公共赋值逻辑:
template <class data_type, int array_size> class StaticArray : public std::array<data_type, array_size>, public ArrayBase<StaticArray<data_type, array_size>, data_type> { using Base = ArrayBase<StaticArray<data_type, array_size>, data_type>; friend Base; public: /** Default constructor. */ StaticArray() : std::array<data_type, array_size>() {} /** Default destructor. */ ~StaticArray() = default; // 显式实现拷贝赋值运算符 StaticArray& operator=(const StaticArray& _other) { if (this != &_other) { this->assign(_other); } return *this; } // 按需添加移动赋值运算符 StaticArray& operator=(StaticArray&&) = default; using Base::operator[]; };
方案2:基类使用模板赋值运算符
如果希望直接在基类保留operator=的实现,可以将其改为模板函数,避免和派生类默认拷贝赋值的签名冲突:
// 在ArrayBase中替换原来的operator=实现 template <typename T> t_derived_class& operator=(const T& _other_derived) { // 可选:添加静态断言约束T的类型,避免接受无效参数 static_assert(std::is_same_v<std::decay_t<T>, t_derived_class>, "只能赋值同类型的派生类实例"); for(std::size_t i = 0; i < Derived.size(); ++i) { Derived[i] = _other_derived[i]; } return Derived; }
这种方式下派生类仍可以保留using Base::operator=的写法,无需显式实现拷贝赋值运算符。
内容的提问来源于stack exchange,提问作者niran90
相关产品推荐
相关产品推荐

