Click here to Skip to main content
Click here to Skip to main content

Tagged as

Constant Member Functions Are Not Always Constant

, 24 May 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
In this article, I'm going to explain why the constant member functions aren't always constant, i.e. despite of the fact that a function is declared as constant, it still allows setting or changing data members within the class

Herakleitos

Introduction

Recently, I had a discussion with my friends about constant member functions in C++ (for example void MyClass::foo const {...}) And one of my friends (he is really great at C++) said that if a member function is const-qualified, then we cannot modify any member variables in the scope of this function. Honestly, such a categorical opinion surprised me and I said, "it's not quite right!!" But all the participants in the debate supported my friend's view. This discussion prompted me to write a short article on the topic about how easy it is to modify the data members of your class in a const function of C++

Background

In fact, even one of the most-read books about C++, called "The C++ Programming Language, Third Edition" by Bjarne Stroustrup, says the following:

"10.2.6 Constant Member Functions [class.constmem]

   class Date 
   {
       int d, m, y;
       public :
          int day () const     { return  d; }
          int month () const { return m; }
          int year () const ;
       // ...
   };

Note the const after the (empty) argument list in the function declarations. It indicates that these functions do not modify the state of a Date.

Naturally, the compiler will catch accidental attempts to violate this promise. For example:

    inline int Date::year () const
    {
       return y ++; // error:  attempt to change member value in const function
    }
  
    When a const member function is defined outside its class, the const suffix is required:
    inline int Date::year () const
    {
       return y ; // correct
    }

And really, if your code tries to change some data member in a const function (by the above manner), you would get an error. When you develop an application by using Visual C++, you will receive the following message:

       error C3490: <your data member> cannot be modified because it is being accessed through a const object

I don't want to argue with the compiler (and even more so with the genial creator of C++) I only want to show another case ...

From my point of view, the author of the book didn't provide full disclosure of this subject, therefore, many programmers understand this subject insufficiently.

The Solution

I use a slightly different technique than the one showed by B.Stroustrup. My approach here allows you to use an interesting trick. The trick may look quite ugly, but it works ...

class User
{
  public:
	User(unsigned int id, unsigned int age, std::string name) 
		: mID(id) , 
		  mAge(age),
		  mName(name)
	{

	}

	void ChangeMe1 (unsigned int id, unsigned int age, std::string name) const;
	void ChangeMe2 (unsigned int id, unsigned int age, std::string name) const;
	void PrintMyData ();
private:
	unsigned int           mID;
	unsigned int           mAge;
        std::string            mName;
};

//To make changes by the pointer (a synonym on this)
void User::ChangeMe1 (unsigned int id, unsigned int age, std::string name) const
{
	// Here can be used and the old C-style cast to remove the constness, i.e.:
        // User * synonym_of_this =  (User *) this;
        User * synonym_of_this = const_cast<User *>(this);


	synonym_of_this->mID   = id; 
	synonym_of_this->mAge  = age;
	synonym_of_this->mName = name; 
}

//To make changes by creating the reference on this
void User::ChangeMe2 (unsigned int id, unsigned int age, std::string name) const
{
	// Here can be used and the old C-style cast to remove the constness, i.e.:
        // const UserPtr &synonym_of_this =  (User *) this;
        const UserPtr &synonym_of_this = const_cast<User *>(this);


	synonym_of_this->mID   = id; 
	synonym_of_this->mAge  = age;
	synonym_of_this->mName = name;
}

void User::PrintMyData ()
{
	std::cout << "ID = " << this->mID << " Age = " << this->mAge <<  " Name = " << this->mName.c_str() << "\n"; 
}

int main()
{
	User presedent_USA (42,46,"Bill Clinton");
	std::cout << "Now the presedent of USA : " << std::endl;
	presedent_USA.PrintMyData();
	
        std::cout << "\nLet's hold an election..." << std::endl;
	presedent_USA.ChangeMe1(43,54,"George Walker Bush");
	std::cout << "\nNow the presedent of USA : " << std::endl;
	presedent_USA.PrintMyData();

	std::cout << "\nLet's hold an election..." << std::endl;
	presedent_USA.ChangeMe2(44,47,"Barack Hussein Obama 2");
        std::cout << "\nNow the presedent of USA : " << std::endl;
	presedent_USA.PrintMyData();
	std::cout << "\n";

	return 0;
}

As you can be see from the above code example we continue to use the const-qualified function, but after starting the following program:

We can see that all members of this class have been changed, i.e. the ChangeMe1, and ChangeMe2 a "const" functions can modify any data members. Apparently the famous greek philosopher Heraclitus was right. In the ChangeMe1 function I used a "workaround" based on accessing data members through a pointer which is a synonym for this. The second solution used in ChangeMe2 is based on creating a reference to this, which behaves also as a synonym for this.

Why is it so important to consider?

  1. The const function can change the data members of class
    (for example, if you deal with scary legacy code and it's necessary to detect the place where some members of a class are changed, then do not ignore the code in the scope of a constant function, because there also may be changes)
  2. If you want to change the data members of a class (for some reason), but it's not possible to change the signature of a method, then you can use the "trick" that I showed. It is important to note that this should be done to resolve problems, but only in very extreme cases. It basically doesn't make any sense to cancel or violate the constancy of constant method, but if you are going to use this "trick", please write detailed comments, to be able to maintain your code. That's all!

History

  • 18nd April 2011: Initial post
  • License

    This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

    Share

    About the Author

    Volynsky Alex
    Software Developer
    Israel Israel
    Mr.Volynsky Alex is a Software Engineer in a leading software company. Alex is skilled in many areas of computer science. He has over 13 years of experience in the design & development of applications using C/C++/STL, Qt, MFC, COM/ActiveX, DirectShow, JavaScript, VBScript, Bash and of course - C#/.NET.
     
    Alex is also interested in the Objective-C development for the iPad/iPhone platforms and he is the developer of the free 15-puzzle game on the App Store.
     
    Overall, Alex is very easy to work with. He adapts to new systems and technology while performing complete problem definition research.
     
    His hobbies include yacht racing, photography and reading in multiple genres.
    He is also fascinated by attending computer meetings in general, loves traveling, and also takes pleasure in exercising and relaxing with friends.
     
    Visit his C++ 11 blog

    Comments and Discussions

     
    GeneralMy vote of 5 Pinmembermk4you713-Jun-12 6:00 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex14-Jun-12 16:04 
    SuggestionMy vote of 5 PinmemberGrigor_I29-May-12 11:13 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex3-Jun-12 9:21 
    GeneralThe Const Nazi | Games from Within PinmemberRolf Kristensen29-May-12 5:05 
    GeneralRe: The Const Nazi | Games from Within PinmemberVolynsky Alex3-Jun-12 9:22 
    GeneralMy vote of 5 PinmemberSteph_Iv28-May-12 11:36 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex3-Jun-12 9:23 
    GeneralMy vote of 5 PinmemberEMogilevsky26-May-12 5:21 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex26-May-12 7:59 
    GeneralMy vote of 5 PinmemberGerard Forestier24-May-12 23:05 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex26-May-12 8:00 
    GeneralMy vote of 3 PinmemberPaul Watt23-May-12 14:39 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex24-May-12 13:49 
    GeneralMy vote of 1 Pinmemberbitterskittles23-May-12 7:53 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex23-May-12 9:35 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex24-May-12 13:40 
    GeneralMy vote of 5 Pinmemberjfriedman23-May-12 5:16 
    AnswerRe: My vote of 5 PinmemberVolynsky Alex23-May-12 5:42 
    QuestionMy vote of 5 PinmemberSharjith23-May-12 4:30 
    AnswerRe: My vote of 5 [modified] PinmemberVolynsky Alex23-May-12 4:40 
    NewsMy vote of 5 PinmemberGlebGeglov23-May-12 1:22 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex23-May-12 2:15 
    GeneralMy vote of 1 PinmemberRolf Kristensen23-May-12 0:37 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex23-May-12 0:40 
    GeneralRe: My vote of 5 Pinmemberjfriedman23-May-12 5:20 
    GeneralMy vote of 1 PinmemberAjay Vijayvargiya22-May-12 22:53 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex23-May-12 0:38 
    GeneralRe: My vote of 5 PinmemberAjay Vijayvargiya23-May-12 2:06 
    I am afraid, those points are not convincing. I would use mutable instead, or write non-const and const overloads for sam function. Casting away const-ness breaks the design.
    GeneralRe: My vote of 5 PinmemberVolynsky Alex23-May-12 4:03 
    GeneralRe: My vote of 5 PinmemberAjay Vijayvargiya23-May-12 5:46 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex23-May-12 6:27 
    SuggestionMy vote of 5 PinmemberY.Desros22-May-12 13:58 
    Questionyou have cast away const... PinmemberS Nelson22-May-12 11:09 
    AnswerRe: you have cast away const... PinmemberVolynsky Alex22-May-12 12:42 
    GeneralRe: you have cast away const... PinmemberPablo Aliskevicius23-May-12 1:20 
    GeneralRe: you have cast away const... PinmemberVolynsky Alex23-May-12 4:33 
    GeneralMy vote of 5 PinmemberS.Goldenzwaig22-May-12 9:21 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex22-May-12 12:45 
    GeneralRe: My vote of 5 PinmemberPaul Watt23-May-12 14:06 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex23-May-12 15:11 
    GeneralMy vote of 3 PinmemberAescleal22-May-12 9:03 
    GeneralRe: My vote of 3 PinmemberMauro Leggieri22-May-12 12:05 
    GeneralRe: My vote of 5 PinmemberVolynsky Alex24-May-12 13:42 
    GeneralRe: My vote of 5 PinmemberMauro Leggieri24-May-12 15:34 
    GeneralRe: My vote of 3 Pinmemberjfriedman23-May-12 5:25 
    QuestionCouple of potential issues with your article PinmemberSimonSays22-May-12 6:58 
    AnswerRe: About my article PinmemberVolynsky Alex22-May-12 13:06 
    AnswerRe: Couple of potential issues with your article Pinmemberjfriedman23-May-12 5:26 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

    | Advertise | Privacy | Terms of Use | Mobile
    Web02 | 2.8.141220.1 | Last Updated 24 May 2012
    Article Copyright 2012 by Volynsky Alex
    Everything else Copyright © CodeProject, 1999-2014
    Layout: fixed | fluid