Compiler Error with const function - c++

I am not sure whether I am missing something basic. But I am unable to understand why the compiler is generating the error for this code:
class A
{
};
class B
{
public:
B();
A* get() const;
private:
A* m_p;
};
B::B()
{
m_p = new A;
}
A* B::get() const
{
//This is compiling fine
return m_p;
}
class C
{
public:
A* get() const;
private:
A m_a;
};
A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}
EDIT: The compiler error is : error C2440: 'return' : cannot convert from 'const class A *' to 'class A *' Conversion loses qualifiers

const in the function signature tells the compiler that the object's members may not be modified. Yet you return a non-const pointer to a member, thus allowing a violation of that promise.
In your class B, you make/break no promise since you don't return a pointer to a member, you return a copy of it (and the member happens to be a pointer).

It's because you're returning a non-const pointer to a member from a const function.
The first part works because you're returning a copy of a member pointer, so this doesn't violate the const-ness of the get function:
class B
{
public:
B();
A* get() const;
private:
A* m_p;
};
A* B::get() const
{
//This is compiling fine
return m_p;
}
But the next bit generates the compile error (on gcc 4)
testfile.cpp:37: error: invalid conversion from ‘const A*’ to ‘A*’
Because your const get function is providing non-const acess to m_a by returning a non-const pointer to it.
class C
{
public:
A* get() const;
private:
A m_a;
};
A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}

Because the returned pointer is not const. Change it to this:
class C
{
public:
const A* get() const;
private:
A m_a;
};
const A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}
Notice that C::get() now returns a const pointer to A.

Member functions marked const cannot return a non-const reference or pointer to a private variable. If the compiler allowed this, anyone outside your class would be able to modify the said private variable and the const qualifier on the function would lose meaning.

This problem can be illustrated with a simpler example:
class MyClass {
public:
int *get() const;
private:
int value;
};
int *MyClass::get() const {
return &value;
}
In MyClass::get() const, value has the type const int. When you dereference it, you get const int *. That type cannot be safely (implicitly) casted to int *. To correct your problem, have get() return const int *.

A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}
Because get() is a const function, the compiler treats all member variables it refers to as const. When you take the address of such a member, you get a pointer to const. But your function is returning a non-const pointer. You need to change your code to
const A* C::get() const
{
return &m_a;
}

Basically just add a const in front,
const A* C::get() const
{
//Compiler generates an error for this. Why?
return &m_a;
}
Then if you want to access it, basically do:
C something;
const A* a = something.get();
However, your program makes very little sense, to me.
IMO, it would make most sense to do:
class A{
};
class C : public A
{
};
That way you don't have to make a "get" that returns the instance of A.

Related

Calling non const method in const method [duplicate]

This question already has answers here:
C++ const method on non const pointer member
(4 answers)
Closed 3 years ago.
#include <iostream>
#include <memory>
class B
{
public:
B(){}
void g() { }
};
class A
{
public:
A()
{
ptr_ = std::make_shared<B>();
}
void f() const
{
ptr_->g(); // compile
//obj_.g(); // doesn't compile as expected
}
std::shared_ptr<B> ptr_;
B obj_;
};
int main()
{
A a;
a.f();
}
I am surprised that this piece of code builds fine. In A::f(), I call a non-const method of a data member. When this data member is a pointer it builds, if it is not a pointer it doesn't build as expected because B::g() is non-const.
Do you understand why I am able to call a non-const function inside a const function ?
The point is who is const in the const member function, the pointer ? the pointee ?
In the const member function f, ptr_, i.e. the pointer itself is considered as const, but not the object pointed by it. You're calling non-const member function g on the pointee, then it's fine.
Furthermore, you can't perform any modification (and call non-const member function) on the pointer ptr_ itself (same as obj_), like ptr_ = std::make_shared<B>();; but you can do this on the object pointed by it, like *ptr_ = B{};.

What are the properties of a const member function's return value, being a pointer?

class B
{
public:
A* GetA() const { return obj; }
private:
A* obj;
}
...
B b;
b.GetA()->AInterfaceMethod(params);
So my questions are:
What would be different had the function not been const?
Are there any restrictions to what I can do with the pointer obtained via GetA()? Is it const? Does it point to a const A?
When is this useful?
I encountered this in an Unreal tutorial (A is forward declared in the tutorial).
EDIT: I probably messed up, but the call does work. I've included the actual Unreal code below:
class ABatteryPickup : public APickup
{
ABatteryPickup()
{
GetMesh()->SetSimulatePhysics(true);
}
}
class Pickup
{
public:
class UStaticMeshComponent* GetMesh() const { return PickupMesh; }
private:
class UStaticMeshComponent* PickupMesh;
}
UStaticMeshComponent::SetSimulatePhysics() is not const.
Also, just tested this on a new, clean C++ project, and it works.
What would be different had the function not been const?
If the function is a non-const member function, you can't call it on a const object.
const B b;
b.GetA(); // Fail, can't call a non-const member function on a const object
Are there any restrictions to what I can do with the pointer obtained via GetA()? Is it const? Does it point to a const A?
No, nothing is different here. The returned value is not const itself, and not a pointer to const, it's just A* as it declared. If the object is const, the member variable obj will be const too, i.e. A* const, note it's still not a pointer to const, i.e. const A*. Anyway you return it by value with type A*, so nothing is different here.
When is this useful?
Const member function and non-const member function could be overloaded. You might use them for different purpose. e.g.
class B
{
public:
A* GetA() { return obj; } // returns A*
const A* GetA() const { return obj; } // returns const A*
private:
A* obj;
}
...
B b;
b.GetA(); // get A*
const B cb;
cb.GetA(); // get const A*
What would be different had the function not been const?
const method has a contract - it does not change internal state of object B directly or indirectly, for example it would not change pointer obj to point somewhere else. So this code:
A* GetA() const { obj = new A; return obj; }
would fail to compile.
Are there any restrictions to what I can do with the pointer obtained via GetA()? Is it const? Does it point to a const A?
No, object of type A is unrelated and to make this method to return pointer of const A you need to change type of the returned pointer:
const A *GetA() const { return obj; } // now you cannot change A through pointer you get, unless you const_cast it.
When is this useful?
You can control separately what you can change inside method and what can be done with object, pointer to which you return. You just have choice.

Cannot call a method of const reference parameter in C++

class A
{
public:
A(){};
~A(){};
void method(){};
};
void call(const A &a)
{
a.method(); // I cannot call this method here if I use "const" but I can call it if not using "const"
}
int main()
{
A a;
call(a);
return 0;
}
In this case, the error is: "passing const A as this argument of void A::method() discards qualifiers [-fpermissive]|"
In function call, if I use const, I get the error, but if I get rid of it, it works.
Can anyone explain it for me?
You can't call non-const member functions via const references. You can fix this by making the member function const:
void method() const {};
^^^^^
This indicates that calling the member does not mutate the object it is called on*
* Conceptually. In practice it can mutate members marked mutable

C++ const method on non const pointer member

I was wondering how protect a non const pointer member from an object throught a const method. For example:
class B{
public:
B(){
this->val=0;
}
void setVal(){
this->val = 2;
}
private:
int val;
};
class A{
public:
A():b(new B){}
void changeMemberFromConstMethod() const{
this->b->setVal();
}
private:
B * b; // how to protect data pointed in A::changeMemberFromConstMethod
}
Is it possible to "protect" A::b data pointed from his method?
After many research on web, no satisfied reponse found yet.
Thanks for your help.
Something like this, perhaps:
template <typename T>
class deep_const_ptr {
T* p_;
public:
deep_const_ptr(T* p) : p_(p);
T* operator->() { return p_;}
const T* operator->() const { return p_;}
};
class A {
deep_const_ptr<B> b = new B;
};
deep_const_ptr behaves like a const T* const pointer in A's const methods, and like T* in non-const methods. Fleshing the class out further is left as an exercise for the reader.
If you change the member of A from
B* b;
to
B b;
then you will get the expected behavior.
class A{
public:
A() : b() {}
void changeMemberFromConstMethod() const{
this->b.setVal(); // This will produce a compiler error.
}
private:
B b;
}
The problem you have is that a const method makes all the member variables const. In this case however, it makes the pointer const. Specifically, it's as if all you have is B * const b, which means a constant pointer to a (still) mutable B. If you do not declare your member variable as const B * b, (that is, a mutable pointer to a constant B), then there is no way to protect from this behavior.
If all you need is a const B, then by all means, define A like this:
class A {
public:
A() : b(new B) {}
// This WILL give an error now.
void changeMemberFromConstMethod() const { b->setVal(); }
private:
const B* b;
}
However, if other methods of A mutate B, then all you can do is make sure that B does not get mutated in your const methods of A.
Try using the following general approach, to protect the const-ness of objects referenced via pointers, in this situation.
Rename B *b
B *my_pointer_to_b;
And change the initialization in the constructor accordingly.
Implement two stubs:
B *my_b() { return b; }
const B *my_b() const { return b; }
Replace all existing references to b with my_b(), in the existing code. Going forward, in any new code, always use my_b() to return the pointer to b.
Mutable methods will get a non-const pointer to B; const methods will get a const pointer to B, and the extra step of renaming makes sure that all existing code is forced to comply with the new regime.

Convert const T* const to T*

is it possibile do this kind of cast in C++?
I need to declare my attribute in this way.
Class A {
public:
void update() { ++i_; }
private:
int i_;
}
Class B{
public:
void foo() {
a_->update(); /* Error */
}
private:
const A* const a_;
}
Error is:
passing ‘const A’ as ‘this’ argument of ‘void A::update()’ discards
qualifiers [-fpermissive]
I try with static_cast, but is not enough.. does not work.. any ideas?
You have two choices here. Either make A::update a const function-
Class A {
void update() const;
}
or remove the constness of the pointer.
Class B{
public:
void foo() {
const_cast<A*>(a_)->update();
}
private:
const A* const a_;
}
The former would be the preferred method, but that will also stop you from doing anything useful in class A's update.
As a rule of thumb, if you have to cast the const off something then you really want to look at why the pointer is const in the first place.
Using a const member with a non-const method is forbiden (unless using mutable). Put a const after declaration of foo() and update():
void update() const { ... }
^^^^^
void foo() const { ... }
^^^^^
or ...
If you don't want to make update a const, you can use const_cast:
void foo() const // Now, this const keyword is optional but recommanded
{
const_cast<A*>(a_)->update();
^^^^^^^^^^^^^^
}
You've got a few options:
use const_cast to cast away the const and call the method.
make update a const method, so that it can be called through a const pointer.
don't store a_ as const in the first place. Change it to A* const a_ so that you can call non-const methods, but the pointer cannot be changed.
Assuming that you cannot declare the method as const and that you know what you are doing (tm) and why this is bad: Try the const_cast!
The const after * has nothing to do with it. You must declare your functions which use a_ as const functions. If they don't compile, you must use const_cast or reinterpret_cast to remove const from the pointer before calling.. But this is very dodgy, and if update() function modifies an object which was originally declared const, this is undefined behaviour.
The error you get
passing ‘const A’ as ‘this’ argument of ‘void A::update()’ discards
qualifiers [-fpermissive]
is result of calling non-const method on a const pointer. This is forbidden. Since you require an update to be non-const and you cannot store a pointer to non_const A, you can use operator const_cast to cast away const and here is how to do it:
class A {
public:
void update(){}
};
class B{
public:
void foo() {
const_cast< A*>(a_)->update(); /* OK*/
}
private:
const A* const a_;
};
You should however rethink your design.
As mentioned by someone before, use mutable/const but this changes your design a little bit:
class A {
public:
void update() const { ++i_; } // this will make the method callable by const A*
private:
mutable int i_; // and this will make you field mutable in a const method
};
class B{
public:
void foo() {
a_->update();
}
private:
const A* const a_;
};