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;
}
答案 0 :(得分:20)
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
有两种类型的const指针。 const成员函数使用我上面列出的那个。
获取所需错误的方法:
尝试更改:
char * rep;
为:
char rep[1024];
并删除此行:
rep = new char [strlen(s)+1];
它将抛出您期望的错误(由于const关键字而无法修改成员)
因为只有一种类型的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成员函数意味着成员函数不会修改对象本身,但并非总是如此,如上例所示。
答案 1 :(得分:4)
原因是你没有改变rep
。如果愿意,您会在代码中的某处找到rep = ...;
。这是
char*const rep;
和
const char* rep;
在你的情况下,如果你执行一个const成员函数,第一个就完成了:指针是const。因此,您将无法重置指针。但是你很可能能够改变指针指向的内容。
现在,请记住rep[i] = ...;
与*(rep + i) = ...;
相同。因此,您更改的不是指针,而是指向的指针。您被允许,因为指针不属于第二种类型。
<强>解决方案强>
physical constness
。但是,const成员函数意味着您的对象是logical const
。如果对某些内容的更改将更改对象的逻辑常量,例如,如果它更改了对象所依赖的某个静态变量,则编译器无法知道您的类现在具有另一个逻辑值。并且它都不知道逻辑值的变化取决于指针指向的内容:编译器不会尝试检查const成员函数中的逻辑const,因为它无法知道这些成员变量的含义。这个东西被称为const-correctness
。std::string
,由某些人提出,或者是一个字符数组(请注意,数组将禁止您更改其内容,而不仅仅是指针),这将是一个合适的选择。 答案 2 :(得分:1)
toUpper()不会更改指针(属于该类)。它只会更改rep指向的数据(不属于该类)。
但是,'const'是对您的类用户的一种保证:如果一个方法被声明为const,那么使用您的类的实例的人可以预期在调用该方法时它不会改变。我的观点是,如果toUpper()改变了字符串的状态,不将它声明为const,C ++是否允许它。
答案 3 :(得分:1)
const限定符意味着它不会改变该类的任何成员。
在这种情况下, rep 是该类的唯一成员,我看不到尝试修改此成员。课程外指向或引用的任何内容都不被视为课程的一部分。
解决这个问题的方法是用std :: string替换char * 然后你只能从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
}
}
答案 4 :(得分:1)
您无法更改声明为
的内容的值const char* rep;
或
const char* const rep;
不幸的是,声明你的成员const变成了代表
char* const rep;
这意味着,您无法更改实际地址,但您可以更改内容,而无法更改值。
为了让const memebrs尊重你的缓冲区const,你需要制作rep和字符数组或字符串对象而不是字符指针。