首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何删除相似常量和非常数成员函数之间的代码重复?

如何删除相似常量和非常数成员函数之间的代码重复?
EN

Stack Overflow用户
提问于 2008-09-24 04:47:11
回答 20查看 45.7K关注 0票数 276

假设我有以下class X,我想在其中返回对内部成员的访问:

代码语言:javascript
复制
class Z
{
    // details
};

class X
{
    std::vector<Z> vecZ;

public:
    Z& Z(size_t index)
    {
        // massive amounts of code for validating index

        Z& ret = vecZ[index];

        // even more code for determining that the Z instance
        // at index is *exactly* the right sort of Z (a process
        // which involves calculating leap years in which
        // religious holidays fall on Tuesdays for
        // the next thousand years or so)

        return ret;
    }
    const Z& Z(size_t index) const
    {
        // identical to non-const X::Z(), except printed in
        // a lighter shade of gray since
        // we're running low on toner by this point
    }
};

两个成员函数X::Z()X::Z() const在大括号内具有相同的代码。这是重复的代码,可能会导致具有复杂逻辑的长函数的维护问题。

有没有办法避免这种代码重复?

EN

回答 20

Stack Overflow用户

回答已采纳

发布于 2008-09-23 20:48:04

是的,可以避免代码重复。您需要使用常量成员函数来获得逻辑,并让非常数成员函数调用常量成员函数,并将返回值重新转换为非常数引用(如果函数返回指针,则为指针):

代码语言:javascript
复制
class X
{
   std::vector<Z> vecZ;

public:
   const Z& z(size_t index) const
   {
      // same really-really-really long access 
      // and checking code as in OP
      // ...
      return vecZ[index];
   }

   Z& z(size_t index)
   {
      // One line. One ugly, ugly line - but just one line!
      return const_cast<Z&>( static_cast<const X&>(*this).z(index) );
   }

 #if 0 // A slightly less-ugly version
   Z& Z(size_t index)
   {
      // Two lines -- one cast. This is slightly less ugly but takes an extra line.
      const X& constMe = *this;
      return const_cast<Z&>( constMe.z(index) );
   }
 #endif
};

注意:重要的是,不要将逻辑放在非常数函数中,并让常量函数调用非常数函数--这可能会导致未定义的行为。原因是常量类实例被转换为非常量实例。非常数成员函数可能会意外地修改类,这将导致C++标准规定的未定义行为。

票数 72
EN

Stack Overflow用户

发布于 2008-09-23 21:24:14

有关详细解释,请参阅Scott Meyer在, 3d ed中的第3项“尽可能使用const”中的标题“避免在const和非const成员函数中复制”,ISBN-13: 9780321334879。

以下是Meyer的解决方案(简化版):

代码语言:javascript
复制
struct C {
  const char & get() const {
    return c;
  }
  char & get() {
    return const_cast<char &>(static_cast<const C &>(*this).get());
  }
  char c;
};

两种类型转换和函数调用可能很难看,但在非const方法中是正确的,因为这意味着对象一开始就不是const。(迈耶斯对此进行了彻底的讨论。)

票数 221
EN

Stack Overflow用户

发布于 2017-11-19 01:51:59

C++17已经更新了这个问题的最佳答案:

代码语言:javascript
复制
T const & f() const {
    return something_complicated();
}
T & f() {
    return const_cast<T &>(std::as_const(*this).f());
}

这样做的好处是:

  • 显而易见
  • 的代码开销最小--它只占用一行代码
  • 很难出错(只能意外丢弃volatile,但volatile是一个罕见的限定符)

< code >F210

如果你想走完整的演绎路线,那么可以通过一个helper函数来实现

代码语言:javascript
复制
template<typename T>
constexpr T & as_mutable(T const & value) noexcept {
    return const_cast<T &>(value);
}
template<typename T>
constexpr T * as_mutable(T const * value) noexcept {
    return const_cast<T *>(value);
}
template<typename T>
constexpr T * as_mutable(T * value) noexcept {
    return value;
}
template<typename T>
void as_mutable(T const &&) = delete;

现在你甚至不能搞乱volatile了,用法看起来像这样

代码语言:javascript
复制
decltype(auto) f() const {
    return something_complicated();
}
decltype(auto) f() {
    return as_mutable(std::as_const(*this).f());
}
票数 66
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/123758

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档