为什么这个const成员函数允许修改成员变量?

发布于 2024-07-08 07:10:50 字数 471 浏览 6 评论 0原文

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;
}
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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

じее 2024-07-15 07:10:50

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 成员函数意味着该成员函数不会修改对象本身,但情况并非总是如此,如上面的示例所示。

A const member function, is a member function that does not mutate its member variables.

const on a member function does not imply const char *. Which would mean that you can't change the data in the address the pointer holds.

Your example does not mutate the member variables themselves.

A const on a member function, will ensure that you treat all of your member variables as const.

That means if you have:

int x;
char c;
char *p;

Then you will have:

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

There are 2 types of const pointers. A const member function uses the one I've listed above.


A way to get the error you want:

Try changing:

char * rep;

to:

char rep[1024];

And remove this line:

rep = new char [strlen(s)+1];

It will throw the error you are expecting (can't modify members because of const keyword)

Because there is only 1 type of const array. And that means you cannot modify any of its data.


Now the whole system is actually broken with the following example:

class String
{

    private:
        char rep2[1024];
        char* rep;

 ...


 String :: String (const char* s)
 {
    rep = rep2;
    strcpy (rep, s); 
 }

So the lesson to learn here is that the const keyword on member functions does not ensure that your object will not change at all.

It only ensures that each member variable will be treated as const. And for pointers, there is a big diff between const char * and char * const.

Most of the time a const member function will mean that the member function will not modify the object itself, but this is not always the case, as the above example shows.

醉殇 2024-07-15 07:10:50

原因是您没有更改rep。 如果愿意,您会在代码中的某处找到 rep = ...; 。 之间的区别

char*const rep;

这是和

const char* rep;

。在您的情况下,如果您执行 const 成员函数,则完成第一个操作:指针是 const。 因此,您将无法重置指针。 但是您很可能能够更改指针所指向的内容。

现在,请记住 rep[i] = ...;*(rep + i) = ...; 相同。 因此,您更改的不是指针,而是指针指向的内容。 允许,因为指针不属于第二种情况类型。

解决方案

  1. 您正在查看的常量含义是物理常量。 但是,const 成员函数意味着您的对象是逻辑const。 如果对某些内容的更改将更改对象的逻辑常量,例如,如果它更改了对象所依赖的某些静态变量,则编译器无法知道您的类现在具有另一个逻辑值。 它也不知道逻辑值的变化取决于指针指向的内容:编译器不会尝试检查 const 成员函数中的逻辑常量,因为它无法知道这些成员变量的含义。 这个东西被称为常量正确性
  2. 使用不仅仅是引用或指针的对象:const 成员函数将使该对象成为 const,并且不允许您更改其内容。 std::string,正如某些人所建议的那样,或者是一个字符数组(请注意,数组不允许您更改其内容,而不仅仅是指针),将是一个合适的选择。
  3. 2.

The reason is that you don't change rep. If you would, you would find rep = ...; somewhere in your code. This is the difference between

char*const rep;

and

const char* rep;

In your case, the first one is done if you execute a const member-function: The pointer is const. So, you won't be able to reset the pointer. But you will very well be able to change what the pointer points to.

Now, remember rep[i] = ...; is the same as *(rep + i) = ...;. Thus, what you change is not the pointer, but what the pointer points to. You are allowed, since the pointer is not of the second case type.

Solution

  1. The const meaning you are looking at is physical constness. However, a const member-function means your object is logical const. If a change to some content will change the logical constness of your object, for example if it changes some static variable that your object depends upon, your compiler cannot know that your class now has another logical value. And neither it can know that the logical value changes dependent on what a pointer points to: The compiler doesn't try to check logical constness in a const member function, since it cannot know what those member variables mean. This stuff is termed const-correctness.
  2. Use an object that is not just a reference or a pointer: A const member function will make that object const, and will disallow you to change its content. std::string, as proposed by some, or an array of characters (note that an array will disallow you changing its content, as opposed to just a pointer), would be an appropriate choice.
  3. 2.

り繁华旳梦境 2024-07-15 07:10:50

toUpper() 不会更改指针(属于该类)。 它仅更改rep指向的数据(不属于该类)。

然而,“const”是对类的用户的一种保证:如果一个方法被声明为 const,那么使用类的实例的人可以期望在调用该方法时它不会改变。 我的观点是,如果 toUpper() 改变了字符串的状态,不要将其声明为 const,无论 C++ 是否允许。

toUpper() does not change the pointer (which belongs to the class). It only changes the data which rep points to (that do not belong to the class).

However, 'const' is a sort of warranty for the users of your class: if a method is declared const, who uses an instance of your class can expect it won't change when calling the method. My point is, if toUpper() changes the state of a string, don't declare it const, whether C++ allows it or not.

猥琐帝 2024-07-15 07:10:50

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

    }
}

The const qualifier means it will not change any members of the class.

In this case rep is the only member of the class and I see no attempt to modify this member. Anything pointed at or referenced outside the class is not considered as part of the class.

A solution to this problem would be to replace the char* with a std::string.
Then you would only be able to call const members of std::string from within toUpper()

For example (use 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

    }
}
吾性傲以野 2024-07-15 07:10:50

const char* rep;

您无法更改声明为或 的

const char* const rep;

,不幸的是,声明您的成员 const 会变成rep

char* const rep;

,这意味着您无法更改实际地址,但可以更改内容,但无法更改值。

为了使 const memebrs 保持缓冲区常量,您需要使代表和字符数组或字符串对象而不是字符指针。

You cannot change the value of something declared as

const char* rep;

or

const char* const rep;

Unfortunately, declaring your member const turns into rep into

char* const rep;

which means, you cannot change the acutal address, but you can change the contents, whereas you cannot change the value.

To make const memebrs respect keep your buffer const, you will need to make rep and array of characters or a string object rather than a character pointer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文