I was going through: C++ FAQs about inheritance and decided to implement it (just to learn it)
#include "Shape.h"
void Shape::print() const
{
float a = this->area(); // area() is pure virtual
...
}
now, everything (well, almost) works as described in item: faq:23.1 except that print() is const and so it can't access the "this" pointer, as soon as you take out const, it works.
Now, C++ FAQs have been around for a while and are usually pretty good. Is this a mistake?
Do they have typo or am I wrong? If I'm wrong, I would like to know how is it possible to access the "this" pointer in a const function.
The problem is that the area() function is not const. If that function was const, then this would compile fine. Since your inside a const function, the this pointer is const and therefore you can only call const functions on it.
Why couldn't this be accessed? The point is, only const members and methods can be used. So if Shape::area() is declared const, there is no problem. Also, you can freely read data member values, but not assign to them:
class Shape
{
int i;
void print() const;
virtual float area() const = 0;
virtual void modify() = 0;
};
void Shape::print() const
{
float a = this->area(); // call to const member - fine
int j = this->i; // reading const member - fine
this->modify(); // call to non const member - error
this->i++; // assigning to member - error
}
If print is defined as const, then it can use this to access const members but not to access non-const members: so it can invoke this->area() if-and-only-if the area method is declared as const (i.e. if the area method promises that if it's invoked then it won't mutate its Shape instance).
It is also a good practice to declare all functions as const by default, and only not do so when you actually need to modify the object. This will also help finding errors of the kind where some function modifies something it is not meant to.
You certainly can access the this pointer, but in a const function it becomes a pointer to a const object. Remember, the this pointer isn't a real pointer instance, so it can change its type at different points in the program.
Related
A co-worker asked about some code like this that originally had templates in it.
I have removed the templates, but the core question remains: why does this compile OK?
#include <iostream>
class X
{
public:
void foo() { std::cout << "Here\n"; }
};
typedef void (X::*XFUNC)() ;
class CX
{
public:
explicit CX(X& t, XFUNC xF) : object(t), F(xF) {}
void execute() const { (object.*F)(); }
private:
X& object;
XFUNC F;
};
int main(int argc, char* argv[])
{
X x;
const CX cx(x,&X::foo);
cx.execute();
return 0;
}
Given that CX is a const object, and its member function execute is const, therefore inside CX::execute the this pointer is const.
But I am able to call a non-const member function through a member function pointer.
Are member function pointers a documented hole in the const-ness of the world?
What (presumably obvious to others) issue have we missed?
The constness of execute() only affects the this pointer of the class. It makes the type of this a const T* instead of just T*. This is not a 'deep' const though - it only means the members themselves cannot be changed, but anything they point to or reference still can. Your object member already cannot be changed, because references cannot be re-seated to point to anything else. Similarly, you're not changing the F member, just dereferencing it as a member function pointer. So this is all allowed, and OK.
The fact that you make your instance of CX const doesn't change anything: again, that refers to the immediate members not being allowed to be modified, but again anything they point to still can. You can still call const member functions on const objects so no change there.
To illustrate:
class MyClass
{
public:
/* ... */
int* p;
void f() const
{
// member p becomes: int* const p
*p = 5; // not changing p itself, only the thing it points to - allowed
p = NULL; // changing content of p in const function - not allowed
}
};
In this context object is a reference to a X, not a reference to a const X. The const qualifier would be applied to the member (i.e. the reference, but references can't be const), not to the referenced object.
If you change your class definition to not using a reference:
// ...
private:
X object;
// ...
you get the error you are expecting.
The instance object of class X is not const. It is merely referenced by an object which is const. Const-ness recursively applies to subobjects, not to referenced objects.
By the alternative logic, a const method wouldn't be able to modify anything. That is called a "pure function," a concept which doesn't exist in current standard C++.
You are calling foo on object, not on this.
Since object is declared as an X&, in a constant CX, it is actually an X& const (which is not the same as const X&) allowing you to call non const methods on it.
One helpful way of thinking about it might be that your X object is not a member of CX at all.
This question already has answers here:
What is the meaning of a const at end of a member function? [duplicate]
(3 answers)
Closed 6 years ago.
There is a class A and it has the following operator() implementation:
void A::operator()(...parameters...) const
{
// operator body
}
What does this const mean?
Methods in C++ can be marked as const like in the above example to indicate that the function does not modify the instance. To enforce this, the this pointer is of type const A* const within the method.
Normally, the this pointer within a method is A* const to indicate that we cannot change what this points to. That is, so that we cannot do this = new A().
But when the type is const A* const we also cannot change any of the properties.
That the method uses this as a const A* and then can only call other const methods.
See this entry of the CPP FAQ.
As already amply described, it means that the method will not modify the observable state of the object. But also, and very importantly, it means the method can be called on a const object, pointer, or reference - a non-const method cannot. ie:
class A
{
public:
void Method1() const
{
}
void Method2()
{
}
};
int main( int /*argc*/, char * /*argv*/ )
{
const A a;
a.Method1(); //ok.
a.Method2(); //compiler error!
return 0;
}
const keyword specifies that the function is a "read-only" function that does not modify the object for which it is called.
It means that calling the operator will not change state of the object.
A const member function promises to not change the observable state of the object.
Under the hood, it might still change state, e.g. of mutable members. However, mutable members should never be visible from anywhere outside the class' interface, i.e. you should never attempt to lie to client code, because client code may validly expect that const functions don't tweak the object's outer hull. Think of mutable as an optimization tool (e.g. for caching and memoization).
Example for mutability:
You have a quadtree class. Under the hood, the quadtree is build up lazily, i.e. on demand; this lazyness is hidden from users of the class. Now, a query-method on that quadtree should be const, because querying a quadtree is expected to not change the quadtree. How do you implement const-correctness and lazyness without breaking C++' rules? Use mutable. Now you have a quadtree that for the user looks const, but you know that under the hood, there's still a lot of change:
class Quadtree {
public:
Quadtree (int depth);
Foo query (Bar which) const;
private:
mutable Node node_;
};
Do const member functions call only const member functions?
class Transmitter{
const static string msg;
mutable int size;
public:
void xmit() const{
size = compute();
cout<<msg;
}
private:
int compute() const{return 5;}
};
string const Transmitter::msg = "beep";
int main(){
Transmitter t;
t.xmit();
return EXIT_SUCCESS;
}
If i dont make compute() a const, then the compiler complains.
Is it because since a const member function is not allowed to modify members, it wont allow
any calls to non-consts since it would mean that the const member function would be 'indirectly' modifying the data members?
Is it because since a const member function is not allowed to modify members, it wont allow any calls to non-consts since it would mean that the const member function would be 'indirectly' modifying the data members?
Yes.
Yes: const member functions only see the const version of the class, which means the compiler will not find any non-const members (data or functions) inside a const member function.
This effect propagates to const objects (instances) of the class, where only const members are accessible.
When applied correctly, const will allow for the programmer to check his use of the class and make sure no unwanted changes are made to any objects that shouldn't be changed.
Yes. When you call 'xmit()', its 'this' pointer will be const, meaning you can't then call a non-const method from there, hence 'compute()' must be const
As others have said; yes.
If there is a particular reason you want compute to be non const, for example if it uses some local cache to store calculations, then you can still call it from other functions that are declared const by declaring a const version
private:
int compute() const{return ( const_cast<Transmitter*>(this)->compute());}
int compute() {return 5;}
Your assertion and your analysis are both correct.
A co-worker asked about some code like this that originally had templates in it.
I have removed the templates, but the core question remains: why does this compile OK?
#include <iostream>
class X
{
public:
void foo() { std::cout << "Here\n"; }
};
typedef void (X::*XFUNC)() ;
class CX
{
public:
explicit CX(X& t, XFUNC xF) : object(t), F(xF) {}
void execute() const { (object.*F)(); }
private:
X& object;
XFUNC F;
};
int main(int argc, char* argv[])
{
X x;
const CX cx(x,&X::foo);
cx.execute();
return 0;
}
Given that CX is a const object, and its member function execute is const, therefore inside CX::execute the this pointer is const.
But I am able to call a non-const member function through a member function pointer.
Are member function pointers a documented hole in the const-ness of the world?
What (presumably obvious to others) issue have we missed?
The constness of execute() only affects the this pointer of the class. It makes the type of this a const T* instead of just T*. This is not a 'deep' const though - it only means the members themselves cannot be changed, but anything they point to or reference still can. Your object member already cannot be changed, because references cannot be re-seated to point to anything else. Similarly, you're not changing the F member, just dereferencing it as a member function pointer. So this is all allowed, and OK.
The fact that you make your instance of CX const doesn't change anything: again, that refers to the immediate members not being allowed to be modified, but again anything they point to still can. You can still call const member functions on const objects so no change there.
To illustrate:
class MyClass
{
public:
/* ... */
int* p;
void f() const
{
// member p becomes: int* const p
*p = 5; // not changing p itself, only the thing it points to - allowed
p = NULL; // changing content of p in const function - not allowed
}
};
In this context object is a reference to a X, not a reference to a const X. The const qualifier would be applied to the member (i.e. the reference, but references can't be const), not to the referenced object.
If you change your class definition to not using a reference:
// ...
private:
X object;
// ...
you get the error you are expecting.
The instance object of class X is not const. It is merely referenced by an object which is const. Const-ness recursively applies to subobjects, not to referenced objects.
By the alternative logic, a const method wouldn't be able to modify anything. That is called a "pure function," a concept which doesn't exist in current standard C++.
You are calling foo on object, not on this.
Since object is declared as an X&, in a constant CX, it is actually an X& const (which is not the same as const X&) allowing you to call non const methods on it.
One helpful way of thinking about it might be that your X object is not a member of CX at all.
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 :)