How to explicitly call const version of the member function? - c++

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();

Related

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().

Const function calling non const or vice versa (to avoid duplication)? [duplicate]

This question already has answers here:
How do I remove code duplication between similar const and non-const member functions?
(21 answers)
C++ template to cover const and non-const method
(7 answers)
Closed 5 years ago.
Is there any advantage using one over the other:
class Foo
{
public:
const int& get() const
{
// stuff here
return myInt;
}
int& get()
{
return const_cast<int&>(static_cast<const Foo*>(this)->get());
}
};
Or
class Foo
{
public:
int& get()
{
// stuff here
return myInt;
}
const int& get() const
{
return const_cast<Foo*>(this)->get();
}
};
I only used the first one, but I just saw the second one used somewhere, so I am wondering.
The comment // stuff here could be a non-trivial check like retrieving the index of a table in order to return a ref on a member of the table (for example: myInt = myTable[myComputedIndex];) so I cannot just make it public. Thus table and any member are not const.
If you have to make a function that is const-agnostic, and avoids duplication, one neat way to do it is delegating implementation to a template, for example
class Foo {
private:
int my_int;
template <typename ThisPtr>
static auto& get(ThisPtr this_ptr) {
return this_ptr->my_int;
}
public:
int& get() {
return get(this);
}
const int& get() const {
return get(this);
}
};
This way you are free from the fear associated with using const_cast, mutable and other stuff that goes into trying to reduce code duplication in cases like this. If you get something wrong, the compiler will let you know.
Ignoring the issue of whether you really need a getter, the best solution when duplicating functionality in both a const and non-const method is to have the non-const method call the const method and cast away the const-ness of the result (i.e. the first of the two alternatives you present in the question).
The reason is simple: if you do it the other way around (with the logic in the non-const method), you could accidentally end up modifying a const object, and the compiler won't catch it at compile time (because the method is not declared const) - this will have undefined behaviour.
Of course this is only a problem if the "getter" is not actually a getter (i.e. if it is doing something more complicated than just returning a reference to a private field).
Also, if you are not constrained to C++11, the template-based solution presented by Curious in their answer is another way of avoiding this problem.
Is there any advantage using one over the other: ...
No, both are bad because they violate the data encapsulation principle.
In your example you should rather make myInt a public member.
There's no advantage to have getters for such case at all.
If you really want (need) getter and setter functions these should look like this:
class Foo
{
private:
mutable int myInt_;
// ^^^^^^^ Allows lazy initialization from within the const getter,
// simply omit that if you dont need it.
public:
void myInt(int value)
{
// Do other stuff ...
myInt = value;
// Do more stuff ...
}
const int& myInt() const
{
// Do other stuff ...
return myInt_;
}
}
You don't say where myInt comes from, the best answer depends on that.
There are 2+1 possible scenarios:
1) The most common case is that myInt comes from a pointer internal to the class.
Assuming that, this is the best solution which avoids both code duplication and casting.
class Foo{
int* myIntP;
...
int& get_impl() const{
... lots of code
return *myIntP; // even if Foo instance is const, *myInt is not
}
public:
int& get(){return get_impl();}
const int& get() const{return get_impl();}
};
This case above applies to pointer array, and (most) smart pointers.
2) The other common case is that myInt is a reference or a value member, then the previous solution doesn't work.
But it is also the case where a getter is not needed at all.
Don't use a getter in that case.
class Foo{
public:
int myInt; // or int& myInt;
};
done! :)
3) There is a third scenario, pointed by #Aconcagua, that is the case of an internal fixed array. In that case it is a toss-up, it really depends what you are doing, if finding the index is really the problem, then that can be factored away. It is not clear however what is the application:
class Foo{
int myInts[32];
...
int complicated_index() const{...long code...}
public:
int& get(){return myInts[complicated_index()];}
const int& get() const{return myInts[complicated_index()];}
};
My point is, understand the problem and don´t over engineer. const_cast or templates are not needed to solve this problem.
complete working code below:
class Foo{
int* myIntP;
int& get_impl() const{
return *myIntP; // even if Foo instance is const, *myInt is not
}
public:
int& get(){return get_impl();}
const int& get() const{return get_impl();}
Foo() : myIntP(new int(0)){}
~Foo(){delete myIntP;}
};
#include<cassert>
int main(){
Foo f1;
f1.get() = 5;
assert( f1.get() == 5 );
Foo const f2;
// f2.get() = 5; // compile error
assert( f2.get() == 0 );
return 0;
}
As you intend access to more complex internal structures (as clarified via your edit; such as providing an operator[](size_t index) for internal arrays as std::vector does), then you will have to make sure that you do not invoke undefined behaviour by modifying a potentially const object.
The risk of doing so is higher in the second approach:
int& get()
{
// stuff here: if you modify the object, the compiler won't warn you!
// but you will modify a const object, if the other getter is called on one!!!
return myInt;
}
In the first variant, you are safe from (unless you do const_cast here, too, which now would really be bad...), which is the advantage of this approach:
const int& get() const
{
// stuff here: you cannot modify by accident...
// if you try, the compiler will complain about
return myInt;
}
If you actually need to modify the object in the non-const getter, you cannot have a common implementation anyway...
Modifying a const object through a non-const access path [...] results in undefined behavior.
(Source: http://en.cppreference.com/w/cpp/language/const_cast)
This means that the first version can lead to undefined behavior if myInt is actually a const member of Foo:
class Foo
{
int const myInt;
public:
const int& get() const
{
return myInt;
}
int& get()
{
return const_cast<int&>(static_cast<const Foo*>(this)->get());
}
};
int main()
{
Foo f;
f.get() = 10; // this compiles, but it is undefined behavior
}
The second version would not compile, because the non-const version of get would be ill-formed:
class Foo
{
int const myInt;
public:
int& get()
{
return myInt;
// this will not compile, you cannot return a const member
// from a non-const member function
}
const int& get() const
{
return const_cast<Foo*>(this)->get();
}
};
int main()
{
Foo f;
f.get() = 10; // get() is ill-formed, so this does not compile
}
This version is actually recommended by Scott Meyers in Effective C++ under Avoid Duplication in const and Non-const Member Function.

Returning reference to a const pointer to const type

Can you look at this example code:
class Test {
int *a;
int b;
public:
Test() : b(2)
{
a = new int(5);
}
const int * const& GetA() const
{
const int * const& c = a;
return a;
}
const int& GetB()
{
return b;
}
~Test()
{
delete a;
}
};
And I get a warning on return a. Why is it wrong to return a reference to a const pointer to a const variable, but it's fine to return a reference to a const variable? By the way if I return c in GetA() it compiles just fine.
Consider first const int& GetB(). That's a neat way of returning a reference to the class member b that can't be modified at the call site. You may as well mark that function const since you are not changing any of the class member data. This is idiomatic C++, especially for types larger than an int, e.g. std::string.
When you write return a;, you are permitting the function call site to modify that class member through that pointer. Although the C++ standard allows this, it circumvents encapsulation and your friendly compiler is warning you of that. Note that since the function itself is not changing the class member, compilation passes despite it being marked as const.
In writing const int * const& c = a; the compiler assumes you know what you're doing.
(As a final note, all havoc is let loose if you attempt to copy an instance of Test due to the compiler generated copy constructor shallow-copying a. You ought to delete the copy constructor and the assignment operators.)

When there is no non-const operator overload, will non-const object use const operator?

It seems it is in VS2013. But why in effective c++' item 3, the non-const operator calls const operator when they do exactly the same thing?
This is the code in Effective c++ item 3:
class TextBlock {
public:
...
const char& operator[](std::size_t position) const // same as before
{
...
...
...
return text[position];
}
char& operator[](std::size_t position) // now just calls const op[]
{
return const_cast<char&>( // cast away const on type;
static_cast<const TextBlock&>(*this)[position] // add const to *this's type;call const version of op[]
);
}
...
};
A const object cannot use a non-const method. (Remember that operators are only methods).
But the converse is true: A non-const object can use a const method (although it will use a non-const equivalent if that's present).
A method is only const if it is marked as const: a compiler is not allowed to assert const-ness by inspecting the function body.
Yes: if a const member function is present, but no non-const version, then calling that function on a non-const object will use the const function.
#include <iostream>
struct Foo {
void bar() const { std::cout << "const bar()\n"; }
};
int main() {
Foo f;
f.bar();
}
prints const bar().
Note the reverse is not true. You may not call a non-const member function on a const object:
struct Foo {
void bar() { std::cout << "non-const bar()\n"; }
};
int main() {
const Foo f;
f.bar();
}
gives a compiler error:
SO.cpp: In function 'int main()':
SO.cpp:9:11: error: passing 'const Foo' as 'this' argument of 'void Foo::bar()' discards qualifiers [-fpermissive]
f.bar();
^
EC++ Item 3, Use const whenever possible has a subsection, Avoiding Duplication in const and Non-const Member Functions. The reason it suggests that you don't just let the compiler pick the const version is that the return types are different (by a const) - the non-const version casts this away:
class CharWrapper {
char c_;
public:
char const& getC() const
{
std::cout << "const getC()\n";
return c_; // pretend this line is complicated
}
char& getC()
{
std::cout << "non-const getC()\n";
char const& c = const_cast<CharWrapper const&>(*this).getC(); // call the right one to avoid duplicating the work
return const_cast<char&>(c); // fix the result type
}
};
int main() {
CharWrapper wrapper;
wrapper.getC() = 'a';
}
Notice that it calls const operator and casts away constness (it one of those few times where it does not result in UB). It is needed so non-const operator returns a mutable reference. Otherwise you would not be able to modify objects contained in vector at all.
Call to existing operator instead of writing code again is done to avoid code duplication and possible future errors when you change one function, but forgot the other.
Regarding your comment: there is no move involved. It returns a reference. I would expect no difference in generated code for both const and non-const operator.

Code with const keyword won't compile

I don't understand why this piece of code won't compile.
I get following error in line return source->GetA();
cannot convert 'this' pointer from 'const class FooStruct' to 'class
FooStruct &'
If I remove the const keyword it compiles fine.
class FooStruct
{
int a;
public:
int GetA() {return a;};
int Bar(const FooStruct *source);
};
int FooStruct::Bar(const FooStruct *source)
{
return source->GetA();
}
The code itself doesn't make sense. It has been stripped down from some real code and its only purpose is to illustrate the problem.
It is because of this line:
return source->GetA();
Here you are trying to execute GetA function on the pointer that you got. If the pointed object is const, the function must also be const, because:
Both const and non-const functions can be executed on non-const objects
Only const functions can be executed on const objects.
It is a good idea to mark all the functions that do not modify the state of the object as const, so they can be used on const objects (e.g. in functions that accept const T & as a parameter).
So in your case, the class should look like:
class FooStruct
{
public:
int GetA() const {return a;}
};
The function GetA itself needs to be marked const:
int GetA() const {
return a;
}
This then allows a const source* pointer to call that function.