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
Related
When I study about override keyword, I found some strange thing like below code.
#include <iostream>
template <class T>
class A
{
public:
virtual void some_function(const T a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
std::cout<<"Base"<<std::endl;
}
};
class Derived : public A<int*>
{
public:
virtual void some_function(const int* a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
std::cout<<"Derived"<<std::endl;
}
};
int main()
{
A<int*>* p = new Derived;
p->some_function(nullptr);
delete p;
}
When I first saw that code, I expected "Derived" to be called.
But above code print result like below.
void A<T>::some_function(T) [with T = int*]
Base
But when I removed const keyword in the some_function that placed in Derived class,
class Derived : public A<int*>
{
public:
virtual void some_function(int* a)
{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
std::cout<<"Derived"<<std::endl;
}
};
It print "Derived".
Can you tell me why this is happening?
The function prototypes are not the same. For T=int* const T a: a is a const pointer to an int, while const int *a is a pointer to an const int. For one the pointer is const, for the other the int is const.
int * const a would be the same as const T a, or you can make T=const int*.
https://godbolt.org/z/WEaEoGh58
Also important to note: When you derive from a class you must declare a virtual destructor.
A hint: when you use the keyword override on the derived function, you will get an error that you are not overriding the function: https://godbolt.org/z/o87GMrhsd
At
const T a
const qualifier is interpreted as top-level cv-qualifier for T, so it is processed
T const a
thus if int* is set to T, parameter type becomes
int* const a
So, your Derived's function signature (it is called second level const qualifier)
const int* a
is different from Base's one. As a result, your Derived virtual function is not called.
In addition, C++ has the rule of "ignore top-level cv-qualifier from function signature". So, your Base's signature
int* const
and if you give the type of
int*
into Derived's signature, these two types signature are interpreted to be equivalent. As a result, your Derived virtual function is called correctly.
The following is a back-ground for your help. The type of
T*
has two component T and pointer and then
T* const
is called top-level cv-qualifier which is applied to *, and then
T const *
is called second level cv-qualifier which is applied to T (equal to const T*). C++ ignore top-level cv-qualifier from signature. On the other hand, second level qualifier is included to signature. Therefore for example,
void f(int*) {}
void f(int* const){}
is failed to compile because of same signature by top-level cv-qualifier ignoring. In contrast,
void f(int*) {}
void f(int const * ){}
is compiled successfully by the difference of second level cv-qualifiers.
This is important to understand the behavior of virtual function calls. The reason is that the signature of derived virtual function and base's one must be identical to call it correctly.
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{};.
I know that when there are both const and non-const versions of a method with the same name and parameters, the version chosen is determined by the const-ness of *this. (constness of the method is part of the signature right?)
But what happens when its being called by another method?
An example
class a{
void b() const{
c();
//do fantastic things
}
const_iterator c() const;
iterator c();
};
When I call b() from a nonconst instance of a, how I know which version of c() gets invoked?
From inside a function declared as const for a type, you can only call the const functions of that type.
But what happens when its being called by another method?
The same thing as when you call it from outside.
Keep in mind that member functions can be pictured as if they had an invisible first parameter T* this. In the case of const member functions, T const* this.
Now, this code:
class a{
void b() const{
c();
//do fantastic things
}
const_iterator c() const;
iterator c();
};
can be thought of as:
class a{
void b(a const* this) const{ // pseudo code
c(this); // pseudo code
//do fantastic things
}
const_iterator c(a const* this) const; // pseudo code
iterator c(a* this); // pseudo code
};
It follows that the const version of c is called, because you "pass it" a pointer to a const, not to a.
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_;
};
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.