class String
{
private:
char* rep;
public:
String (const char*);
void toUpper() const;
};
String :: String (const char* s)
{
rep = new char [strlen(s)+1];
strcpy (rep, s);
}
void String :: toUpper () const
{
for (int i = 0; rep [i]; i++)
rep[i] = toupper(rep[i]);
}
int main ()
{
const String lower ("lower");
lower.toUpper();
cout << lower << endl;
return 0;
}
5 回答
一个 const 成员函数,是一个不改变其成员变量的成员函数。
成员函数上的 const 并不意味着 const char *。这意味着您无法更改指针所在地址中的数据。
您的示例不会改变成员变量本身。
成员函数上的 const 将确保您将所有成员变量视为 const。
这意味着如果您有:
int x;
char c;
char *p;
然后你将拥有:
const int x;
const char c;
char * const p; //<-- means you cannot change what p points to, but you can change the data p points to
有 2 种类型的 const 指针。一个 const 成员函数使用我上面列出的那个。
一种获得所需错误的方法:
尝试改变:
char * rep;
到:
char rep[1024];
并删除这一行:
rep = new char [strlen(s)+1];
它会抛出您期望的错误(由于 const 关键字而无法修改成员)
因为只有 1 种类型的 const 数组。这意味着您无法修改其任何数据。
现在整个系统实际上被以下示例破坏了:
class String
{
private:
char rep2[1024];
char* rep;
...
String :: String (const char* s)
{
rep = rep2;
strcpy (rep, s);
}
所以这里要吸取的教训是成员函数上的 const 关键字并不能确保您的对象根本不会改变。
它只确保每个成员变量都将被视为 const。对于指针,const char * 和 char * const 之间存在很大差异。
大多数时候,一个 const 成员函数意味着该成员函数不会修改对象本身,但并非总是如此,如上面的示例所示。
原因是你没有改变rep
。如果你愿意,你会rep = ...;
在你的代码中找到某个地方。这是之间的区别
char*const rep;
和
const char* rep;
在您的情况下,如果您执行 const 成员函数,则第一个完成:指针是 const。因此,您将无法重置指针。但是您很可能能够更改指针指向的内容。
现在,记住rep[i] = ...;
是一样的*(rep + i) = ...;
。因此,您更改的不是指针,而是指针指向的内容。您是被允许的,因为指针不是第二种情况类型。
解决方案
- 您正在查看的 const 含义是
physical constness
. 但是, const 成员函数意味着您的对象是logical const
. 如果对某些内容的更改将更改对象的逻辑常量,例如,如果它更改了对象所依赖的某些静态变量,则编译器无法知道您的类现在具有另一个逻辑值。而且它也不知道逻辑值的变化取决于指针指向的内容:编译器不会尝试检查 const 成员函数中的逻辑常量,因为它不知道这些成员变量的含义。这种东西被称为const-correctness
。 - 使用不只是引用或指针的对象:const 成员函数将使该对象成为 const,并且不允许您更改其内容。
std::string
,正如一些人所建议的那样,或者一个字符数组(请注意,一个数组将不允许您更改其内容,而不仅仅是一个指针),将是一个合适的选择。
2.
toUpper() 不会更改指针(属于该类)。它只会更改 rep 指向的数据(不属于该类)。
但是,'const' 是对类的用户的一种保证:如果一个方法被声明为 const,那么使用你的类的实例的人可以期望在调用该方法时它不会改变。我的观点是,如果 toUpper() 改变了字符串的状态,无论 C++ 是否允许,都不要将其声明为 const。
const 限定符意味着它不会更改类的任何成员。
在这种情况下, rep是该类的唯一成员,我看不到修改该成员的尝试。在类之外指向或引用的任何内容都不被视为类的一部分。
解决此问题的方法是将 char* 替换为 std::string。
那么您将只能从 toUpper() 中调用 std::string 的 const 成员
例如(使用 std::string)
class String
{
std::string rep;
void toUpper() const
{
for (int i = 0; rep [i]; i++)
rep[i] = toupper(rep[i]);
// Can only use const member functions on rep.
// So here we use 'char const& std::string::operator[](size_t) const'
// There is a non const version but we are not allowed to use it
// because this method is const.
// So the return type is 'char const&'
// This can be used in the call to toupper()
// But not on the lhs of the assignemnt statement
}
}
您不能更改声明为的东西的值
const char* rep;
或者
const char* const rep;
不幸的是,声明你的成员 const 变成 rep 成
char* const rep;
这意味着,您不能更改实际地址,但可以更改内容,而不能更改值。
为了使 const memebrs 尊重保持你的缓冲区 const,你需要制作代表和字符数组或字符串对象而不是字符指针。