如何消除C++中const与非const版本operator()的代码重复
问题描述
假设我们正在实现矩阵类二维数据结构,计划使用operator()作为元素访问接口,参考实现代码如下:
template <std::size_t M, std::size_t N> class Matrix { protected: std::array<float, M*N> arr; public: float operator()(const std::size_t &m, const std::size_t &n) const { assert(m < M); assert(n < N); return this->arr[m*N + n]; } float& operator()(const std::size_t &m, const std::size_t &n) { // 和上面const版本的函数体完全一致 assert(m < M); assert(n < N); return this->arr[m*N + n]; } // 构造函数等其余代码省略 };
我们需要同时保留这两个operator()重载,支持const对象的访问场景,例如const Matrix mat = {1, 0, 1, 0}; std::cout << mat(0,0) << std::endl;这类用法。但目前两个重载的函数体逻辑完全重复,需要在不改变原有功能的前提下消除冗余。
实现方案
完全可以实现,这也是C++中const/非const成员函数去重的标准惯用法,注意调用方向一定是非const版本调用const版本,绝对不能反过来——const成员函数承诺不修改对象状态,调用非const版本会打破这个约束,属于未定义行为。
具体实现只需要两步类型转换,把公共的边界检查、索引计算逻辑全放在const版本里即可:
- 在非const重载中,先把当前
this指向的对象显式转为const引用,避免递归调用非const版本自身 - 调用const版本的
operator()拿到结果后,用const_cast去掉返回值的const限定,因为当前调用的对象本身是非const的,这个转换是完全安全的。
另外原实现中const版本返回float值会产生不必要的拷贝,可以优化为返回const float&,功能完全一致,效率更高。优化后的无冗余完整代码如下:
template <std::size_t M, std::size_t N> class Matrix { protected: std::array<float, M*N> arr; public: // 公共逻辑全部写在const版本中,返回const引用避免拷贝 const float& operator()(const std::size_t &m, const std::size_t &n) const { assert(m < M); assert(n < N); return this->arr[m*N + n]; } // 非const版本直接复用const版本的逻辑 float& operator()(const std::size_t &m, const std::size_t &n) { return const_cast<float&>( static_cast<const Matrix<M, N>&>(*this)(m, n) ); } // 构造函数等其余代码保持不变 };
这个实现和原有功能完全等价:const对象调用时得到不可修改的const引用,非const对象调用时得到可修改的普通引用,支持mat(0,0) = 1.0f这类赋值操作,边界检查逻辑只需要维护一份,后续修改索引规则、校验逻辑时只需要改const版本即可,不会出现两个重载逻辑不一致的问题。
内容的提问来源于stack exchange,提问作者Cheiron
相关产品推荐
相关产品推荐

