Const 正确的类设计
在 const
-correct 类中,所有不改变逻辑状态的成员函数都具有 this
cv-qualified 为 const
,表示它们不修改对象(除了任何 mutable
字段,即使在 const
实例中也可以自由修改) ); 如果 const
cv-qualified 函数返回一个引用,那么该引用也应该是 const
。这允许在常量和非 cv 限定的实例上调用它们,因为 const T*
能够绑定到 T*
或 const T*
。反过来,这允许函数在不需要修改时将它们的传递引用参数声明为 const
,而不会丢失任何功能。
此外,在 const
正确的类中,所有传递的参考函数参数都将是正确的,如 Const Correct Function Parameters
中所讨论的那样,因此只有在函数明确需要修改它们时才能修改它们。
首先,让我们来看看 this
cv-qualifiers:
// Assume class Field, with member function "void insert_value(int);".
class ConstIncorrect {
Field fld;
public:
ConstIncorrect(Field& f); // Modifies.
Field& getField(); // Might modify. Also exposes member as non-const reference,
// allowing indirect modification.
void setField(Field& f); // Modifies.
void doSomething(int i); // Might modify.
void doNothing(); // Might modify.
};
ConstIncorrect::ConstIncorrect(Field& f) : fld(f) {} // Modifies.
Field& ConstIncorrect::getField() { return fld; } // Doesn't modify.
void ConstIncorrect::setField(Field& f) { fld = f; } // Modifies.
void ConstIncorrect::doSomething(int i) { // Modifies.
fld.insert_value(i);
}
void ConstIncorrect::doNothing() {} // Doesn't modify.
class ConstCorrectCVQ {
Field fld;
public:
ConstCorrectCVQ(Field& f); // Modifies.
const Field& getField() const; // Doesn't modify. Exposes member as const reference,
// preventing indirect modification.
void setField(Field& f); // Modifies.
void doSomething(int i); // Modifies.
void doNothing() const; // Doesn't modify.
};
ConstCorrectCVQ::ConstCorrectCVQ(Field& f) : fld(f) {}
Field& ConstCorrectCVQ::getField() const { return fld; }
void ConstCorrectCVQ::setField(Field& f) { fld = f; }
void ConstCorrectCVQ::doSomething(int i) {
fld.insert_value(i);
}
void ConstCorrectCVQ::doNothing() const {}
// This won't work.
// No member functions can be called on const ConstIncorrect instances.
void const_correct_func(const ConstIncorrect& c) {
Field f = c.getField();
c.do_nothing();
}
// But this will.
// getField() and doNothing() can be called on const ConstCorrectCVQ instances.
void const_correct_func(const ConstCorrectCVQ& c) {
Field f = c.getField();
c.do_nothing();
}
然后我们可以将它与 Const Correct Function Parameters
结合起来,使类完全正确。
class ConstCorrect {
Field fld;
public:
ConstCorrect(const Field& f); // Modifies instance. Doesn't modify parameter.
const Field& getField() const; // Doesn't modify. Exposes member as const reference,
// preventing indirect modification.
void setField(const Field& f); // Modifies instance. Doesn't modify parameter.
void doSomething(int i); // Modifies. Doesn't modify parameter (passed by value).
void doNothing() const; // Doesn't modify.
};
ConstCorrect::ConstCorrect(const Field& f) : fld(f) {}
Field& ConstCorrect::getField() const { return fld; }
void ConstCorrect::setField(const Field& f) { fld = f; }
void ConstCorrect::doSomething(int i) {
fld.insert_value(i);
}
void ConstCorrect::doNothing() const {}
这也可以与基于 const
ness 的重载相结合,如果实例是 const
我们想要一个行为,如果不是则需要不同的行为; 一个常见的用途是提供访问器的 constainers,如果容器本身是非 const
,则只允许修改。
class ConstCorrectContainer {
int arr[5];
public:
// Subscript operator provides read access if instance is const, or read/write access
// otherwise.
int& operator[](size_t index) { return arr[index]; }
const int& operator[](size_t index) const { return arr[index]; }
// ...
};
这通常用在标准库中,大多数容器提供重载以考虑 const
ness。