C ++类的严格性

时间:2011-07-20 13:47:31

标签: c++ const

class SomeClass {
  public:
    void Render() const;

  private:
     mutable Cache m_some_cache;
};

上面的类是否正确?我何时可以安全地说“此操作不会更改实例的内部状态”?

在上面的示例中,SomeClass是在屏幕上呈现内容的东西。它使用缓存(例如OpenGL缓冲区对象)来允许更快地处理进一步的调用。所以内部改变的唯一事情就是缓存对象。我问自己缓存是否已经属于渲染器的内部状态。

这个例子很小,但是在我的实际应用程序中,这是一个有很多类的道路,即涉及很多Render()调用,而且大多数只进行缓存。但是有些人还通过资源加载器加载资源 - 这里的假设是正确的,即使查询资源管理器加载资源,方法也可能是const吗?

6 个答案:

答案 0 :(得分:6)

当我们说“内部状态不会改变”时,我们指的是纯粹的 逻辑 事物。 逻辑 决定是否更改m_some_cache会更改对象状态。正确性是 逻辑 问题。因此,如果您认为从用户的角度来看,更改m_some_cache不会影响对象状态(在 逻辑 意义上),则代码为const -correct。

在您的特定情况下,我认为没关系。

答案 1 :(得分:4)

这样想。这完全有效:

void Type::print_self () const {
    std::cout << *this << std::endl;
}

您不是在修改对象本身,因此使用const限定符是完全有效的。此方法正在修改std::cout,但这不会计入const的{​​{1}}范围。

尽管如此,Type::print_self()在我看来是矛盾的,除非你只在mutable Cache内使用Cache元素进行本地存储。如果您真的将它用作缓存,那么将此元素限定为Render似乎有点可疑。将它用作缓存(例如,通过调用mutable而不是调用Render)并且您已经欺骗了编译器和类的用户。

修改
根据OP的评论,Render方法确实是Render的图形等价物。可能不会通过渲染来修改对象的“真实”状态(可能是为了构造最小工作示例而未示出)。将print_self()指定为Render方法是正确的做法。如果const数据成员的原因是作为速度缓冲,以避免每次调用Cache时构建和破坏它的成本,那么将Render成员限定为Cache(需要mutable才能保留Render)。

答案 2 :(得分:3)

  

我什么时候可以安全地说“此操作不会改变实例的内部状态”?

这个问题是合乎逻辑的。通常,可变成员不被视为内部状态,而是被视为实现工件。 所以,你班级的文档通常应该描述被认为是内部状态的内容,它可以单独留下可变成员。

const仅涉及对象的内部状态。 const - 方法可以合法地改变外部状态。在这里我想到了指针类比:char * const p是一个常量指针,但它可以改变指向的值。所以你的资源管理器示例似乎也是正确的。

答案 3 :(得分:2)

正如@ildjarn所观察到的,const-correctness指的是可观察的,而不是对象的内部状态;这就是mutable有用的原因。

然后再次,如果你实际渲染的东西,那么表示屏幕的对象的可观察状态不能合理地const,恕我直言,因为如果你以后添加它会破坏一种检查方法,用于找出屏幕上/帧缓冲区中的内容。

如果SomeClass不代表屏幕,那么我希望Render可以引用一个Screen对象的可变引用作为参数。从逻辑上讲,某些内容必须更改,即使它不是SomeClass实例。

答案 4 :(得分:2)

正确性是关于从外部看到的对象的状态。

如果对成员函数的所有调用都继续返回相同的结果,则对象的状态在逻辑上是相同的。

答案 5 :(得分:2)

要问自己的问题是,“就用户而言,调用Render函数是否会改变对象的已定义状态或未来行为?”

假设您的缓存实际上只是一个资源缓存,那么可能修改缓存并不会改变功能行为,只是让它更快。由于您的课程不能保证它的速度有多慢,因此就调用者而言,这不会改变已定义的状态或行为。因此,它是mutable成员的有效候选人,可由const成员函数修改。