In C++ Primer P259, it says
Objects that are const, and references or pointers to const objects,
may call only const member functions.
Based on my current understanding, however, pointers to const objects not necessarily applies because the pointer itself is nonconst. As long as the member function does not modify the object being pointed to, it's legal to call nonconst member functions on pointers to const objects.
Is it correct?
Edit: OK I get it now, it is because when we "call member function on the pointer", we are actually dereferencing it first, and use the object underneath.
The quote is correct.
Try this
class TestClass
{
public:
void nonconst(){};
void constMethod() const {}
};
int main()
{
TestClass const *s = new TestClass();
//s->nonconst(); // (1) no not legal
s->constMethod();
s = new TestClass(); // (2) yes legal
s->constMethod();
}
s is a pointer to a constant. Calling a non const method causes
passing ‘const TestClass’ as ‘this’ argument discards qualifiers [-fpermissive]
However s can point to a different instance. As said in the comments the pointer can be pointed to a different variable.
Related
Today I found out that code like that works. That sounds really strange to me, because as far as I always knew you can't modify any of members from const member function. You actually can't do it directly, but you can call non-const member function. if you mark member function as const that means that this pointer passed to the function is pointing to const object, then how non-const member function is called in the example bellow?
#include <iostream>
class X
{
public:
void foo() const
{
ptr->bar();
}
void bar() {}
private:
X * ptr;
};
int main()
{
}
Your member variable is not X, but pointer to X. As long as foo does not modify the pointer, it can be const.
When you have a pointer member, then the pointer is const in a const method. You won't be allowed to change the address stored in the pointer. But you can change the pointee all you like.
It's the difference between
X* const cannot_change_pointer; //this is how top-level const applies to pointers
const X* cannot_change_pointee;
What's even more interesting is that const on a method has no effect whatsoever on reference members for the same reason (a const method would only prevent you making a reference refer to something else which can't be done with a reference anyway).
That's seems perfectly OK. The call to foo does not modify the ptr member. Hence, the constness of foo is respected.
my 2 cents
I know a const method cannot modify the object from which it is called. Look at this code:
class A{
int a;
public:
void f(A & a_) const {
a_.a=5;
};
};
int main(){
A x;
x.f(x);
return 0;
}
Why does this code compile? Why can I even assign a reference to a non const object of the same class, when declaring the method as constant? In general how can the compiler check all the possible situations in which the function could modify the object?
I know a const method cannot modify the object from which it is called.
This is an oversimplification, and slightly inaccurate.
A const function merely means that the implicit this pointer is a pointer to const.
Why does this code compile?
Because it is well-formed.
Why can I even assign a reference to a non const object of the same class, when declaring the method as constant?
Because constness of the function does not affect what objects you can modify through a reference.
In general how can the compiler check all the possible situations in which the function could modify the object?
The compiler simply does not make such checks.
A const member function cannot modify the object from which it is called using the "implicit" this parameter. f(...) is (ignoring member visibility) equivalent to the free function
void f(const A* this, A& _a) {
_a.a = 5;
}
If you pass the same object as a non-const pointer or reference, you are still allowed to modify it.
I have two classes TestClass and OtherClass, where TestClass has a member variable of type OtherClass named m_otherClass. Note that this is not declared to be const.
In the minimal example provided below; when m_otherClass is a pointer, then everything compiles and runs fine. If I change this to be a non-pointer, then I get compiler errors (the changes are commented out in the minimal example):
"Non-const function 'setOtherMember' is called on const object"
error: passing 'const OtherClass' as 'this' argument discards qualifiers [-fpermissive] m_otherClass.setOtherMember();
#include <iostream>
#include <memory>
class OtherClass {
public:
void setOtherMember() {
m_otherMember = 2;
std::cout << "Other member is now 2" << std::endl;
}
private:
int m_otherMember = 0;
};
class TestClass {
public:
TestClass(): m_otherClass(std::make_unique<OtherClass>())
// TestClass()
{}
void myMethod() const {
m_otherClass->setOtherMember();
// m_otherClass.setOtherMember();
}
private:
std::unique_ptr<OtherClass> m_otherClass;
// OtherClass m_otherClass; // If changing to this I get the error!!
};
int main() {
TestClass testClass;
testClass.myMethod();
return 0;
}
Is this because myMethod() is const (and then promising not to change any member variables), whereas setOtherMember() is non-const and is changing OtherClass's member variable, and then indirectly also the m_otherClass object?
But why does this not fail then when m_otherClass is a pointer?
And why does the compiler error says that passing 'const OtherClass' as 'this'argument fails, when m_otherClass has not been declared to be const?
Const qualified member functions in most cases aren't allowed to change an object's members state. This means, that every member which is not mutable can not be modified in this function body. When dealing with pointers, you just say, that you won't modify a pointer value, not a pointee itself. It is because constness of a pointer is not propagated on its pointee.
In the upcoming standards it will be possible to change this behaviour by using propagate_const.
A simpler example to demonstrate the difference.
struct Foo { int m; };
const Foo f = {10};
f.m = 20; // Not allowed since modifying f.m modifies f.
struct Bar { int* p; };
int i = 10;
int j = 20;
const Bar b = {&i};
b.p = &j; // Not allowed since modifying b.p modifies b.
*(b.p) = j; // Allowed since it does not change b or b.p. It changes the value
// of what b.p points to.
When you put const on a method, all your data members are treated as being const. And that is why you get the error when you have OtherClass as a value, since it turns into a value of const OtherClass.
Now when you use a pointer of OtherClass you get const std::unique_ptr<OtherClass> and the const applies only to the pointer but not to the value it points to.
But why does this not fail then when m_otherClass is a pointer?
Because it is const correct to modify an object pointed by a const pointer, as long as it is a pointer to non-const such as in your case.
And why does the compiler error says that passing 'const OtherClass' as 'this'argument fails, when m_otherClass has not been declared to be const?
myMethod is declared const. Therefore this is a pointer to const. Therefore the lvalue this->m_otherClass is also const regardless of whether the object named by the lvalue is const or not.
I have C++ code that when I compile it I get the following error message:
error: no matching function for call to ‘DataSourceScheme::initObject(const QString&, const QString&, QVector<ColumnScheme*>* const&)’
initObject(datasourcescheme.name_, datasourcescheme.cmd_, datasourcescheme.columns_);
note: no known conversion for argument 3 from ‘QVector<ColumnScheme*>* const’ to ‘const QVector<const ColumnScheme*>*
The C++ code:
DataSourceScheme::DataSourceScheme(const DataSourceScheme &datasourcescheme) {
initObject(datasourcescheme.name_, datasourcescheme.cmd_, datasourcescheme.columns_);
}
void DataSourceScheme::initObject(const QString &name, const QString &cmd, const QVector<const ColumnScheme*> *columns) {
name_ = name;
cmd_ = cmd;
columns_ = new QVector<ColumnScheme*>();
if (columns != NULL) {
for (const ColumnScheme *column : *columns) {
addColumn(*column);
}
}
}
Please help
Thanks!
Perhaps you need clarification on the usage of const. foo* const A declares an object of type foo and creates a constant pointer to that object. The object can be changed but not the pointer. const foo* creates a pointer to a constant object. The object foo is not modifiable.
You are trying to pass a constant pointer to a list of editable objects to a function which requires a pointer to a list of constant objects. Do you see where this leads to problems? The usage within the function does not match the criteria set at the creation of the objects being passed.
You can pass a normal pointer to a function requiring a constant pointer. This conversion is OK, i.e.
void func(foo* const param); // Function declaration
foo* A;
func(A); // Function call OK
Also,
void func(foo* const param); // Function declaration
foo* const A;
func(A); // Function call OK
You cannot pass a pointer to a constant object to a function requiring a normal pointer. This conversion is OK, i.e.
void func(foo* param); // Function declaration
const foo* A;
func(A); // Error
I will add a side note. The use of void func(foo* const param); is good practice IMHO to signify that the function func is not expected to delete, manage memory, or reassign the pointer. This is why many microsoft API calls use the const keyword. They merely use the object but in no way manage it.
Today I found out that code like that works. That sounds really strange to me, because as far as I always knew you can't modify any of members from const member function. You actually can't do it directly, but you can call non-const member function. if you mark member function as const that means that this pointer passed to the function is pointing to const object, then how non-const member function is called in the example bellow?
#include <iostream>
class X
{
public:
void foo() const
{
ptr->bar();
}
void bar() {}
private:
X * ptr;
};
int main()
{
}
Your member variable is not X, but pointer to X. As long as foo does not modify the pointer, it can be const.
When you have a pointer member, then the pointer is const in a const method. You won't be allowed to change the address stored in the pointer. But you can change the pointee all you like.
It's the difference between
X* const cannot_change_pointer; //this is how top-level const applies to pointers
const X* cannot_change_pointee;
What's even more interesting is that const on a method has no effect whatsoever on reference members for the same reason (a const method would only prevent you making a reference refer to something else which can't be done with a reference anyway).
That's seems perfectly OK. The call to foo does not modify the ptr member. Hence, the constness of foo is respected.
my 2 cents