Const member functions

In the previous example, we kept the struct very simple. Since the struct didn't have any member functions, we only needed to worry about when non-member functions want to modify the data. However, object-oriented programming suggests that we shouldn't have data be public. Instead, all data should be private and accessed through public member functions. Let's look at a very simple example to understand this concept:

class Simple 
{
public:
Simple(void)
{
m_data = 0;
}
void SetData(int data)
{
m_data = data;
}
int GetData(void)
{
return m_data;
}
private:
int m_data;
};

int main(void)
{
Simple s;
const Simple cs;

s.SetData(10); //Works as Expected
int value = s.GetData();//Works as Expected

cs.SetData(10); //Error as expected
value = cs.GetData(); //Error: Not Expected
return 0;
}

As expected, when our class is not marked as const, we can use both the SetData and GetData member functions. However, when we mark our class as const, we expect that we won't be able to use the SetData member function, because it modifies the data. However, unexpectedly, we can't use the GetData member function, even though it doesn't modify the data at all. To understand what is going on, we need to understand how member functions are called and how a member function modifies the correct data.

Whenever a non-static member function is called. The first parameter is always the hidden this pointer. It is a pointer to the instance that is calling the function. This parameter is how the SetData and GetData can act upon the correct data. The this pointer is optional within the member function, as programmers, we can choose to use it or not:

//Example showing the hidden this pointer. This code won't //compile 
Simple::Simple(Simple* this)
{
this->m_data = 0;
}
void Simple::SetData(Simple* this, int data)
{
this->m_data = data;
}
int Simple::GetData(Simple* this)
{
return this->m_data;
}

This is completely true. The this pointer is actually a const pointer to a Simple class. We didn't talk about const pointers, but it just means the pointer can't be modified, but the data it points to (the Simple class) can be. This distinction is important. The pointer is const, but the Simple class is not. The actual hidden parameter would look something like this:

//Not Real Code. Will Not Compile 
Simple::Simple(Simple* const this)
{
this->m_data = 0;
}

When we have code like this that calls a member function:

Simple s; 
s.SetData(10);

The compiler is really turning it into code that looks like this:

Simple s; 
Simple::SetData(&s, 10);

This is the reason we get errors when we try to pass a const Simple object to the member function. The function signature is not correct. The function does not accept a const Simple object. Unfortunately, since the this pointer is hidden, we cannot simply make the GetData function accept a const Simple pointer. Instead we must mark the function as const:

//What we would like to do but can't 
int Simple::GetData(const Simple* const this);

//We must mark the function as const
int Simple::GetData(void) const;

We must mark the function as const within the class as well. Notice that SetData is not marked const, because the purpose of that function is to modify the class, but GetData is marked const because it only reads data from the class. So, our code would look something like the following. To save space, we didn't include the function definitions again:

class Simple 
{
public:
Simple(void);
void SetData(int data);
int GetData(void) const;
private:
int m_data;
};

int main(void)
{
Simple s;
const Simple cs;

s.SetData(10); //Works as Expected
int value = s.GetData();//Works as Expected

cs.SetData(10); //Error as expected
value = cs.GetData(); //Works as Expected
return 0;
}

As you can see, by marking the GetData member function as const, it can be used when the variable instance is marked const. Marking member functions as const allows the class to work correctly with non-member functions that may be attempting const correctness. For example, a non-member function (possibly written by another programmer) trying to display a Simple object by using the GetData member function:

//Const correct global function using member functions to access 
//the data
void DisplaySimple(const Simple& s)
{
std::cout << s.GetData() << std::end;
}

Since DisplaySimple isn't intending to change the data in the class, the parameter should be marked as const. However, this code will only work if GetData is a const member function.

Being const-correct takes a little work and may seem difficult at first. However, if you make it a habit, it will eventually become the natural way that you program. When you are const-correct, your code is cleaner, more protected, self-documenting, and more flexible, because you are prepared for const and non-const instances. As a rule, if your function isn't going to modify the data, mark the parameter as const. If the member function isn't going to modify the class data, mark the member function as const.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.120.187