我有一个成员函数,它被声明为 const 并通过指针修改数据。这似乎具有误导性。我应该删除 const 关键字吗?
我想知道其他人如何在他们的代码中处理这种情况。人们是否只是添加评论以澄清发生了什么?他们不将 const 关键字添加到成员函数吗?也许完全是别的东西?
任何建议表示赞赏。
我有一个成员函数,它被声明为 const 并通过指针修改数据。这似乎具有误导性。我应该删除 const 关键字吗?
我想知道其他人如何在他们的代码中处理这种情况。人们是否只是添加评论以澄清发生了什么?他们不将 const 关键字添加到成员函数吗?也许完全是别的东西?
任何建议表示赞赏。
您基本上有两种选择:
深度常数:
class Foo
{
T * ptr;
public:
T & operator*() { return *ptr; }
T const & operator*() const { return *ptr; }
T * operator->() { return ptr; }
T const * operator->() const { return ptr; }
};
浅常量:
class Foo
{
T * ptr;
public:
T & operator*() const { return *ptr; }
T * operator->() const { return ptr; }
};
这真的取决于你,也取决于你上课的目的。如果该类是智能指针,那么具有浅常量语义似乎是合理的,因为该类应该尽可能类似于原始指针(当然,您可以有一个指向非常量指针的常量原始指针)。
否则,您应该问自己为什么要公开对成员指针对象的访问权限。您当然有可能希望通过对您的类的持续引用来提供可变访问,但我想这些都是特殊和罕见的情况。首先,您的代码中不应该有那么多原始指针。通过取消引用一个指针来返回一个深度常量引用应该没问题,但通常在更好封装的“getter”函数中,它隐藏了你的类中有一个指针的事实,比如T const & get() const { return *ptr; }
.
一般来说,是的。即使您可以做到,修改您声明为常量的内容也是一种欺骗性行为。
如果有人使用您的代码并看到 const,他们期望 const。修改,即使对你来说是明智的,也可能会给他们带来严重的问题——甚至使程序崩溃。
考虑一个std::vector<Blah>
成员与Blah*
用于实现动态数组的成员。大多数情况下,用前者代替后者是有意义的。对于Blah*
成员const
,允许方法修改数组中的数据,而对于std::vector<Blah>
成员,const
不允许方法修改那里的数据。
还要考虑一个带有索引方法的矩阵类,该方法返回允许分配给元素的代理。通过代理分配会改变矩阵,而不是代理对象本身。因此,代理对象的赋值运算符可以是(并且应该是)const
,以便对其效果施加尽可能多的约束,而其主要工作是修改事物。
这是设计级别与编码级别不同的另一个示例。
在第一个示例中,使用成员数组,const
所有关于表达设计级别约束,但在第二个示例中,使用分配代理,const
所有关于表达编码级别约束。
然而,这些用法并非不兼容。关键思想是为代码的读者提供尽可能多的约束(因为这大大减少了理解或处理代码必须考虑的不同事物的数量)。结果:const
在您实际可以添加的任何地方添加。