Is C++ guaranteed to call a certain constness of member function? - c++

If I have the following:
class A {
int foo() const {
j++;
return i;
}
int& foo() {
return i;
}
int i;
mutable int j;
};
then obviously something like
A a;
a.foo() = 5;
calls the non-const version. But what conditions need to be met to make sure that a call is to the const or non-const version for a few examples...
int i = a.foo(); //I would expect to call the const. Is it guaranteed?
const int j = a.foo(); //Ditto
const int& l = a.foo(); //Ditto
int& k = a.foo(); //I would expect the non-const
foobar(k); //foobar is "void foobar(int)"
return; //but the compiler could potentially decide the const version is fine.

const function gets called when the object itself is const.
int i = static_cast<const A>(a).foo(); //calls const function
Also see this code for better understanding: (must read the comments)
void f(const A &a) //a is const inside the function
{
int i = a.foo(); // calls const function
}
void h(A &a) //a is non-const inside the function
{
int i = a.foo(); // calls non-const function
}
A a;
f(a);
h(a); //pass the same object!
See the online demo : http://ideone.com/96flE

The constness of a decides which function - what you do with the return value is not a part of overload resolution. All your samples would call the non-const version.

Return values are never considered when determining which overload to take.
Also, when a is declared as
A a;
then the non const version takes precedence.
If a is declared as
const A a;
then the const version can be called only.

Whether your member function call resolves to a const member function or not, depends on the constness of the "this" pointer i.e. the object on the LHS of dot or arrow operator that is implicitly passed to the called member function.
Resolves to non const:
A a;
a.foo();
Resolves to const:
void bar(const A& a)
{
a.foo();
}

Related

Why const correctness rule doesn't work for built in libraries?

There is a rule about const methods. If the method is const, and we are trying to use another function at the same method, so it should be const as well. Otherwise, we will have a compilation error. I was trying to find the declaration of abs() function in math.h library, and here is what I found: Declarations of abs()
It means that the abs() function is not const, but when I use it inside const method I am not having a compilation error. can somebody explain why is that?
class D:public B,C
{
public:
D()
{
cout<<"This is constuctor D"<<endl;
}
int fun3() const;
~D()
{
cout<< "Destructor D"<<endl;
}
};
int D::fun3() const
{
int x=-3;
return abs(x);
}
To start, unlearn what you think you know. Let's look at what it means to be a const member.
class D {
public:
int fun2();
int fun3() const;
};
What does this declare? There is a class called D. There are two member functions fun2 and fun3, each taking a hidden this parameter and no other parameters.
Hold on! A hidden parameter? Well, yes. You can use this within the function; its value has to come from somewhere. All non-static member functions have this hidden parameter. However, not all non-static member functions have the same type of hidden parameter. If I were to show the hidden parameter, the declarations would look like the following:
int D::fun2(D * this);
int D::fun3(const D * this);
Notice how the const exists inside this pseudo-declaration? That is the effect of declaring a const member function: this points to a const object rather than a non-const object.
Now back to the question. Can fun3 call fun2? Well, fun3 would pass its this pointer (a pointer-to-const-object) to fun2, which expects a pointer-to-object. That would mean losing constness, so it's not allowed.
Can fun3 call abs? Well, fun3 would pass an integer to abs. No problem here. The problem is losing the constness of this. As long as you avoid that, you're fine.
There is a misunderstanding here about the constraint of const member functions.
A const member function can call whatever function it wants, as long as it doesn't change the state of the object. So fun3() compiles perfectly well, since it doesn't change any member variable and it doesn't call any non-const member functions for the same object.
Important note: public B,C might not be what you think: it means that D inherits publicly from B and privately from C. If you want it to inherit publicly from C you must state public B, public C.
const being applied to a method just means that the this pointer, i.e. the pointer to the instance on which the method is operating, is const. This implies that it cannot modify the fields and can only call const methods on it, not in general.
Calling a free function is perfectly acceptable, or even calling a non-const method on a different object of the same class, as long as such object is not const.
Consider this
#include <iostream>
int f(int num) { return num+1; }
int fr(int& num) { return num+1; }
int fcr(const int& num) { return num+1; }
class D
{
public:
int value= 0;
public:
void f1() { value++; }
int f2() const { return value; }
int f3() { return value; }
static void f4() { std::cout << "Hello" << std::endl; }
void f5() const;
};
void D::f5() const
{
// Prohibited:
// f1(); // modifies this
// f3(); // might modify this
// value++; // modifies this->value, thus modifies this
// value= 2; // modifies this->value, thus modifies this
// value= abs(value); // modifies this->value, thus modifies this
// fr(value); // takes value by reference and might modify it
//
// Permitted:
f2(); // const function, does not modify this
std::cout << value << std::endl; // independent function, does not modify this; read access to this->value is const
std::cout << abs(value) << std::endl; // independent function, does not modify this; read access to this->value is const
f4(); // static function, does not modify this
f(value); // function, does not modify this; takes value as read only (makes copy)
fcr(value); // function, does not modify this; takes value as read only by reference
D otherObject;
otherObject.f1(); // modifies otherObject (non const), does not modify this
}
int main()
{
const D d;
d.f5();
}
Whenever you call a member function like f4() inside f5() you're passing an implicit this pointer equivalent to this->f4(). Inside f5(), as it is const, this is not of type D* but rather const D*. So you can't do value++ (equivalent to this->value++ for a const D*. But you can call abs, printf or whatever that does not take this and tries to modify it).
When you take this->value if this type is D* it's type is int and you're free to modify it. If you do the same with a const D*, its type becomes const int, you cannot modify it, but can copy it and access it as a const reference for reading.

Why is the `int* Get()` called insted of `const int& Get()`?

I have a class B that has two methods, where one returns a pointer to a member variable and the other returns a const reference to the variable.
I try to call those methods. During the calls, I store the return values to respective return types.
I was expecting the appropriate return types would end up calling the appropriate methods, but I get a compilation error saying:
error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
const int& refval2 = b.Get(); `
Here is my code:
#include <iostream>
class B{
public:
int* Get(){
return &x_;
}
const int & Get() const{
return x_;
}
private:
int x_ = 0;
};
int main(){
B b;
const int& refval2 = b.Get();
int* pval2 = b.Get();
}
Return type is not part of function signature, it's not considered in overload resolution.
In general, the candidate function whose parameters match the arguments most closely is the one that is called.
For non-static member function call, the type of the object to be called on involves too. There're two Get(), one is const and one is non-const. For b.Get();, the non-const Get() is an exact match; for the const Get() to be called the object b has to be converted to const. Then the non-const one wins, after that the compiler will try to convert the returned int* to const int& and fails.
So
B b;
int* pval2 = b.Get(); // call to non-const Get()
const B cb;
const int& refval2 = cb.Get(); // call to const Get()
Why is the int* Get() called insted of const int& Get()?
const int & Get() const
Is a const member function.
From class.this:
If the member function is declared const, the type of this is const X*
However, you declared:
B b;
as non-const which will call the non-const function int* Get(). Thus, the error.
There are two things
return type are not considered in overload resolution
Const ness of method is considered in over load resolution
If you remove const in second method, compiler will complain about ambiguity.
As already answered return type is not considered. So I see 3 possible solutions:
1 make it part of function signature:
class B {
public:
void Get( int *&refptr );
void Get( int &refval ) const;
};
int main(){
B b;
int refval2 = 0;
b.Get( refval2 );
int* pval2 = nullptr;
b.Get( pval2 );
}
but this produces pretty ugly code, so you better use method 2 or 3 -
2 use different function names, this is pretty obvious
3 use ignored parameter:
class B {
public:
int *Get( nullptr_t );
const int &Get() const;
};
int main(){
B b;
const int &refval2 = b.Get();
int* pval2 = b.Get( nullptr );
}
The problem is that the compiler thinks the two Get() functions are the same. If you create two identical functions with only varying return types, the compiler has no idea which function you want to use. To fix the problem, change the name of one or both of the Get() functions; say GetXPtr() and GetX().

How to explicitly call const version of the member function?

I have an overloaded member function in single class. The differences between two return type and const modifier:
class A
{
public:
int mass() const {return m_mass;}
protected:
int& mass() {return m_mass;}
private:
int m_mass;
};
But by default having non-const instance of class A will cause non-const version of overloaded function to be called:
int main()
{
A a;
return (const int)a.mass();
}
error: int& A::mass() is protected within this context
How can the const version be called explicitly in this case?
You simply use a named const reference to it, or better still, use const_cast to obtain an unnamed const reference to it, then call.
int main()
{
A a;
//1
const A& a_const = a;
a_const.mass();
//2
const_cast<const A&>(a).mass();
//3
//in C++17
//std::as_const(a).mass(); //3
}
With C++17 and later you can use std::as_const.
C++17 will introduce std::as_const, which is a really simple utility that you can implement yourself until then:
A a;
std::as_const(a).mass();

Why is this allowed?

So I know it is disallowed to have functions with the same parameters and names:
int a(int b) {
return b;
}
int a(int b) {
return b;
}
int main() {
int c = a(4);
}
This above won't compile. But then I got thinking, what if I passed one by reference, and one by value?
int a(int b) {
return b;
}
int a(int& b) {
return b;
}
int main() {
int c = a(4);
}
The above does compile, I guess because you can't pass 4 to by reference, so it assumes you want the first a, which means the compiler can distinguish which function you want to call. If I then change main to this:
int main() {
int c = a(4);
a(c);
}
It will fail to compile, I assume because c can be passed to either function, so the compiler doesn't know which function to call.
But what about... THIS?
int a(const int& b) {
return b;
}
int a(int& b) {
return b;
}
int main() {
int c = a(4);
a(c);
}
This does compile. Why? I expected it to not, because c can be passed to both the first and second a. Is there some misconception I have?
My question specifically is, how come this (code below) does not compile, and the final one does?
int a(int b) {
return b;
}
int a(int& b) {
return b;
}
int main() {
int c = a(4);
a(c);
}
If I was the compiler, and I could choose which function to call based how close the parameters matched, for the call a(c), I could choose from both the first and second. Is there any reason that the first or second a cannot be chosen from in this example?
The process of choosing the correct function to use from a function call is called Overload Resolution. When a function is called, the compiler searches for all functions with that name (overloads) and compiles them into an overload set. Simply put, a best match is chosen by picking the functions that require the least conversions as possible from their parameters.
These are the two functions compiler chooses from a(c):
int a(const int& b);
int a( int& b);
The second overload is chosen because the first overload requires a const-qualification. The variable with which you called the function with, c, is non-const, so it is a perfect match for the second overload and can be bound to the non-const reference.
int a(const int& b) {
return b;
}
int a(int& b) {
return b;
}
int main() {
int c = a(4);
a(c);
}
When you call it with a(4) 4 is a literal and only your version taking a const reference can bind it, so that's the one being called.
Now when you call a(c) you got c as a non-const int it will therefore prefer the function taking a non-const reference.

friend function returning reference to private data member

I have two questions about the following code.
class cls{
int vi;
public:
cls(int v=37) { vi=v; }
friend int& f(cls);
};
int& f(cls c) { return c.vi; }
int main(){
const cls d(15);
f(d)=8;
cout<<f(d);
return 0;
}
Why does it compile, since f(d) = 8 attemps to modify a const object?
Why does it still print 15, even after removing the const attribute?
It is not modifying a const object as a copy of d is being made due to the argument of f() being passed by value and not by reference. This is also the reason that d is unchanged as it is not being modified.