The question: Why can a const member function sometimes modify a data member and sometimes not?
The explanation: The code below is an excerpt from working code in my baseline at work.
I have a Calculator class that owns a data member called "theLayout" (Header and Implementation defined below). The calculator class has a const member function called "Parms()" which returns a smart pointer to a Parms object that theLayout owns (by calling its own Parms() function).
The calculator class has a const member function called calculateStart() which sets (i.e. modifies) the reference returned from calling the Parms() function in the Calculator class.
This seems to contradict the meaning of const to me. If the const member function cannot modify the this pointer, then why can it set a value on one of the data members (theLayout) that it owns? Doesn't this "modify" the this pointer of the Calculator instance, and thus contradict the meaning of a const member function? Does this work because theLayout is a pointer?
Calculator Class
//Header
class Calculator
{
public:
Calculator();
//ParmsPtr is refcounted smart pointer
const ParmsPtr& parms() const {return theLayout->parms();}
protected:
void calculateStart() const; //Why does this work?
//It seems more intuitive that this should be declared as:
void calculateStart() //with no const modifier.
Layout& theLayout;
}
//Implementation
void Calculator::calculateStart() const
{
parms()->setStart(1);
}
Layout Class
//Header
class Layout : public RefCountedObject
{
public:
Layout();
//ParmsPtr is refcounted smart pointer
inline const ParmsPtr& parms() const;
private:
ParmsPtr theParms;
}
//Implementation
inline const ParmsPtr& Layout::parms() const
{
if (!theParms)
{
Layout* nonConstThis = const_cast<Layout*>(this);
ParmsPtr parms = new Parms();
nonConstThis->setParms(parms);
}
return theParms;
}
The calculator class has a const member function called calculateStart() which sets (i.e. modifies) the reference returned from calling the Parms() function in the Calculator class.
Yes, calculateStart() does modify the Calculator object, which is unexpected considering the final const qualifier in its definition.
Why ? Look at definition of inline const ParmsPtr& Layout::parms() const; the final const tells the compiler that the function will not modify the Layout object, though it actually does. How ? By mischeviously const_cast'ing the object to a non-const object; that's where the constness is broken and that's why setParms() can be called.
This is a bad practice, though there may be some reasons to do it. In such cases, const_cast serves this purpose.
The critical question is, what exactly is being made const by declaring start() to be const? The answer is the reference, not the value referenced.
In your example, inside the start() method, the compiler sees the data member as having type Layout const&, which is not the same as const Layout&. The same thing applies to pointers. If your data member was a pointer type, the compiler would see the type as Layout const*.
Related
i'm trying to understand class getters and setters functions...
My question is:
If i design a function that just only get a state from its class (a "getter" function), why mark it as "const member function"?
I mean, why use a const member function if my function is designed to not change any proprieties of its class?
i don't understand please :(
for example:
int GetValue() {return a_private_variable;}
and
int GetValue() const {return a_private_variable;}
what is the real difference?
When you declare a member function as const, like in
int GetValue() const;
then you tell the compiler that it will not modify anything in the object.
That also means you can call the member function on constant object. If you don't have the const modifier then you can't call it on an object that has been defined as const. You can still call const member functions on non-constant objects.
Also note that the const modifier is part of the member function signature, which means you can overload it with a non-const function. That is you can have
int GetValue() const;
int GetValue();
in the same class.
const can show up in three different places in C++.
Example 1:
const Object obj1;
obj1 is a const object. Meaning that you can not change anything on this object. This object can only call const member functions like
int GetValue() const {return a_private_variable;}
Example 2:
int myMethod() const {//do something}
This is a const method. It would be a const member function if it is declared inside of a class. These are the types of methods that const variables can call.
Example 3:
int myMethod(const Object &x) {//do something with x}
This is a method that takes a const parameter. This means that the logic inside myMethod is not allowed to change anything to do with x. Also note the parameter is being passed by reference not by copy. I like to think of this as a read only type of method.
When you are developing software that will be used by others; it is a good idea to not let them break things they don't know they should not break. In this case you can constrain variables, methods, and parameters to be const to guaranteed that the contract is upheld. I tried to summarize the main ideas I learned in college, but there are many resources online around const in C++. Check out this link if you would like to know more. Also it is possible that I remembered somethings incorrectly as I have not been in the C/C++ realm for a while.
A const instance of a class can only call const functions.
Having a const instance of a class is useful for making your programs more stable since then you can't modify the instance by accident.
In your case the functions do exactly the same thing, but it doesn't have to be that way.
I have class Foo and its member bar_ is a pointer to some data. Method modify modifies the data, but not the pointer itself. Therefore I can declare the method as const:
class Foo {
public:
Foo() : bar_(new double) {};
void modify() const {*bar_ += 1;};
private:
double *bar_;
};
If I declare the method as const, it will accessible from other const methods, which is more flexible. At the same time I can drop const as a hint for other developers and users that method modifies the data indirectly (and let think that the data is owned by the class). So I have a choice here: declare modify as const or drop const: void modify() const or void modify().
What are pros and cons of each approach? What do guidelines say? What should I do?
const after a method declaration is a statement of intent - const methods are meant to be idempotent; they do not modify the state of the object and can be called on const instances.
If the value pointed-to by bar_ is part of the object's state, then a const method should not modify it.
In addition, even the name modify() sounds like it modifies the object in some way, and thus should not be declared const.
But also the other way is important - if a method does not modify the state, it is recommended to declare it const (see C++ Core Guideline Con.2).
I have the following class interface:
class Test
{
public:
Test();
static void fun() const;
private:
int x;
static int i;
};
Test.cpp contains fun()'s implementation:
void Test::fun() const
{
cout<<"hello";
}
it is giving me errors... modifiers not allowed on static member functions
What does the error mean? I want to know the reason why I am not able to create a function which is static as well as const.
void fun() const;
means that fun can be applied to const objects (as well as non const).
Without the const modifier, it can only be applied on non const object.
Static functions by definition need no object.
A member function being const means that the other non-const members of the class instance can't be called.
A free function isn't a member function, so it's not associated as to a class or class instance, so it can't be const as there is no member.
A static function is a free function that have it's name scoped inside a class name, making it always relative to a type, but not associated to an instance of that type, so there is still no member to get access to.
In those two last cases, there is no point in having const access, as there is no member to access to.
Static functions work without an instance, whereas const guarantees that the function will not change the instance (even though it requires an instance).
It may be easier to understand if you see the translated code:
static void fun();
at the end of the day is translated to a function that takes no argument, namely
void fun();
For the other example,
void fun() const;
at the end of the day is translated to a function of the form
fun(const Test& self)
Thus, static void fun() const has two contradictory meanings.
BTW: This translation occurs for all member functions (const or not)
i answered this a few hours ago here: Why we need to put const at end of function header but static at first?
(SO system is not happy with my response. automatically converted to comment)
Perhaps it would help to have a simple code example.
class Foo {
public:
static void static_function();
void const_function() const;
};
// Use of static function:
Foo::static_function();
// Use of const function:
Foo f;
f.const_function();
The key difference between the two is that the const function is a member function -- that is, it is invoked on instances of the Foo class. That means you first need to instantiate an object of type Foo, and then that object acts as the receiver of the call to const_function. The const itself means that you won't modify the state of the object which is the receiver of that function call.
On the other hand, a static function is essentially a free function, where you can call it without a receiving object. Outside the scope of the class where it's defined, however, you'll need to qualify it using the class name: Foo::static_function.
This is why it doesn't make sense to have a function which is both static and const, as they're used in entirely different contexts. There's no need to worry about modifying the state of any object when invoking a static function because there is no receiving object -- it is simply invoked like a free function.
Because a static const function of a class does not make sense. const means that a thing (object/variable) stays the same. Static means that a thing object etc stays the same in that context.
I have an a class which is singleton as defined follows
class myData {
private:
myData (void); // singleton class.
// Copy and assignment is prohibted.
myData (const myData &);
myData & operator=(const myData &);
static myData* s_pInstance;
public:
~myData (void);
static const myData & Instance();
static void Terminate();
void myFunc() { cout << "my function..." ;}
};
// In cpp file.
myData* myData::s_pInstance(NULL);
myData::myData(){}
myData::~myData()
{
s_pInstance = NULL;
}
const myData& myData::Instance()
{
if (s_pInstance == NULL)
{
s_pInstance = new myData();
}
return *(s_pInstance); // want to avoid pointer as user may deallocate it, so i used const referense
}
void main() {
(myData::Instance()).myFunc();
}
I am getting following error
error C2662: 'myData::myFunc' : cannot convert 'this' pointer from 'const myData' to 'myData&'
how to avoid above problem and call a function from Instance function which is returning const reference?
Thanks!
You'd want to declare func() as a constant member function, so the compiler knows it won't violate the const'd return value from the instance() function.
You could instead also make the instance() function return a 'regular' reference as apposed to a const one.
So either turn:
void myFunc() into void myFunc() const
Or turn:
const myData& myData::Instance() into myData& myData::Instance()
If you are calling a function on a const reference, the function you call must also be const, in your case void myFunc() const.
Otherwise you might return a non-const reference, if that works better.
The error says that myData::Instance() is a const instance of the class, and it can't call myFunc() on that, because myFunc() might change the instance, and you can't change a const instance.
Of course, you know that myFunc() can't really change the instance, but you must advertise this fact, as follows:
void myFunc() const { cout << "my function..." ;}
Avoiding the whole discussion of whether Singleton is a good to have pattern or the source of all evil, if you are actually implementing a singleton, chances are that const correctness will not work there as you expect it, so you should be aware of some pitfalls.
First your error: your Instance() static member returns a const reference, and that means that you can only perform operations that do not modify the object, i.e. call member functions marked as const, or use public members if present in a way that do not modify their values. My suggested solution is modify Instance() to return a non-const reference, rather than making func() const as others suggest.
Now for a longer explanation to the problem of const-correctness in general when applied to your particular Singleton problem. The basic problem is that when you implement a type, you divide those members that modify the object from those that don't, and you mark the latter as const member functions so that the compiler knows of your promise (allows you to call that method on a constant object) and helps you not break it (complains if you try to modify the state in the definition of the method). A method that is marked as const can be applied to both a constant and non constant object, but a method that is not marked const can only be applied to an object that is not const.
Back to the original piece of code, if you implement a singleton and the only way of accessing the object is by an Instance() method that returns a const reference, you are basically limiting all user code to use only const methods implemented in your interface. That means that effectively either all methods are non-mutating, or they are useless (const_cast should never be used). That in turn means that if you have any non-const operation you want to provide an Instance() method that returns a non-const reference.
You could consider implementing two variants of Instance(), but that will not be really helpful. Overload resolution will not help in user code to determine which version to use, so you will end up having to different methods: Instance(), ConstInstance() (choose your names), which means that it is up to user code to determine which one to use. The small advantage is that in their code, the choice of accessor will help documenting their intended usage, and maybe even catch some errors, but more often than not they will just call the non-const version because it works.
Too much C# and too little C++ makes my mind dizzy... Could anyone remind me what this c++ declaration means? Specifically, the ending "const". Many thanks.
protected:
virtual ostream & print(ostream & os) const
A const method will simply receive a const this pointer.
In this case the this pointer will be of the const ThisClass* const type instead of the usual ThisClass* const type.
This means that member variables cannot be modified from inside a const method. Not even non-const methods can be called from such a method. However a member variable may be declared as mutable, in which case this restriction will not apply to it.
Therefore when you have a const object, the only methods that the compiler will let you call are those marked safe by the const keyword.
The ending const means that the print function shouldn't be able to change the state of any of the members of the class it is declared in (and therefore cannot call any member functions of that class which are not also declared const).
In the example below, the print function in the class Foo cannot change any of the member variables of Foo (unless they are declared mutable), and cannot call any non-const functions in Foo.
class Foo {
public:
Foo(string value) { m_value = value; }
protected:
ostream & print(ostream & os) const {
m_value = string("foobar"); // won't compile
os << m_value;
return os;
}
private:
string m_value;
};
The const on the method declaration tells the compiler that the function is safe to call on a const object of the type the function is a member of. It also signals to the compiler that the function is not supposed to alter the state of the object and it will not be able to change any member variables that are not marked as mutable.
If you omit the const, this code will not work:
const Foo bar;
bar.print(std::cout); // Will fail to compile unless 'print' is marked const
You're declaring a protected virtual method named print which takes as a parameter a reference to an ostream and returns a reference to an ostream.
The const keyword means the method won't be able to alter the state of the object, the this pointer will be const.
A virtual method is a method whose behavior can be overridden within an inheriting class, basically the virtual keyword gives C++ its' ability to support polymorphism.
And finally if you don't know what is a reference go there
Comming from C# I suppose you know what protected means :)