tags:

views:

1585

answers:

5
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;
}
A: 

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.

Federico Ramponi
+1  A: 

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

    }
}
Martin York
+7  A: 

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.

Brian R. Bondy
mahesh
+4  A: 

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.
Johannes Schaub - litb
+1  A: 

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.

JohnMcG