This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I remove code duplication between similar const and non-const member functions?
i have two members
A &B::GetA (int i)
{
return *(m_C[m_AtoC[i]]);
}
const A &B::GetA (int i) const
{
return *(m_C[m_AtoC[i]]);
}
for now i just duplicate code, but may be there exists nice way to do it. I certanly dont want to deal with type cast from const to non-const.
EDIT: So i want to call one member frm another to avoid code duplication.
[Note the correction; sorry for getting it the wrong way round initially.]
This is an appropriate situation for using a const_cast, and it allows you to deduplicate code by forwarding the call from the non-const function to the corresponding const function:
A & B::GetA(int index)
{
return const_cast<A &>(static_cast<B const *>(this)->GetA(index));
}
It's important to note that this should only be done in one direction: You can implement the non-const method in terms of the constant one, but not the other way round: The constant call to GetA() gets a constant reference to the object in question, but since we have additional information that it's actually OK to mutate the object, we can safely cast away the constness from the result.
There's even a chapter on precisely this technique in Scott Meyer's Effective C++.
You could do something like:
class B {
public:
A& GetA (int index) { return GetA_impl(index); }
const A& GetA (int index) const { return GetA_impl(index); }
private:
A& GetA_impl (int index) const { return *(m_C[m_AtoC[i]]); }
};
I'm not sure it's really worth the effort in this case, but this can be useful if the potentially duplicated code gets more complicated.
You can avoid const_cast with a little template metaprogramming.
// This meta function returns a const U if T is const, otherwise returns just U.
template <typename T, typename U>
make_same_const<T, U>
{
typedef typename std::conditional<
std::is_const<T>::value,
typename std::add_const<U>::type,
U
>::type type;
};
// Generic version of a function. Constness of return type depends on
// constness of T.
// This is a static member template of B.
template <typename T>
make_same_const<T, A>::type& B::GetA(T& obj, int i)
{
return *(obj.m_C[obj.m_AtoC[i]]);
}
A& B::GetA(int i) { return B::GetA(*this, i); }
A const& B::GetA(int i) const { return B::GetA(*this, i); }
IMO this isn't enough code (or complexity) to be worth de-duplicating.
As you can see in both the const_cast-based solutions, the cast expression is actually longer than the original code.
If you have a longer or more complex expression you're really worried about, though, please show it.
Assuming the bodies of GetA() and GetA() const are identical (which means GetA() doesn't modify *this), you can safely use one const_cast to implement the const version using the non-const one:
const A& B::GetA() const {
return const_cast<B*>(this)->GetA();
}
The non-const GetA() doesn't modify the object, so calling it on a const B object is not undefined. The non-const reference returned by non-const GetA() is converted to a const& before being returned out of GetA() const, so there's no danger of undefined behaviour there either.
How about
const A &B::GetA (int index) const
{
return *(const_cast<B*>(this)->GetA(index));
}
Related
I tried to wrap something similar to Qt's shared data pointers for my purposes, and upon testing I found out that when the const function should be called, its non-const version was chosen instead.
I'm compiling with C++0x options, and here is a minimal code:
struct Data {
int x() const {
return 1;
}
};
template <class T>
struct container
{
container() {
ptr = new T();
}
T & operator*() {
puts("non const data ptr");
return *ptr;
}
T * operator->() {
puts("non const data ptr");
return ptr;
}
const T & operator*() const {
puts("const data ptr");
return *ptr;
}
const T * operator->() const {
puts("const data ptr");
return ptr;
}
T* ptr;
};
typedef container<Data> testType;
void testing() {
testType test;
test->x();
}
As you can see, Data.x is a const function, so the operator -> called should be the const one. And when I comment out the non-const one, it compiles without errors, so it's possible. Yet my terminal prints:
"non const data ptr"
Is it a GCC bug (I have 4.5.2), or is there something I'm missing?
If you have two overloads that differ only in their const-ness, then the compiler resolves the call based on whether *this is const or not. In your example code, test is not const, so the non-const overload is called.
If you did this:
testType test;
const testType &test2 = test;
test2->x();
you should see that the other overload gets called, because test2 is const.
test is a non-const object, so the compiler finds the best match: The non-const version. You can apply constness with static_cast though: static_cast<const testType&>(test)->x();
EDIT: As an aside, as you suspected 99.9% of the time you think you've found a compiler bug you should revisit your code as there's probably some weird quirk and the compiler is in fact following the standard.
It doesn't matter whether Data::x is a constant function or not. The operator being called belongs to container<Data> class and not Data class, and its instance is not constant, so non-constant operator is called. If there was only constant operator available or the instance of the class was constant itself, then constant operator would have been called.
But testType is not a const object.
Thus it will call the non const version of its members.
If the methods have exactly the same parameters it has to make a choice on which version to call (so it uses the this parameter (the hidden one)). In this case this is not const so you get the non-const method.
testType const test2;
test2->x(); // This will call the const version
This does not affect the call to x() as you can call a const method on a non const object.
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.
I am beginner in cpp language.
Recently I saw in a many classes declare twice the same function with a little different such as:
int& operator[](size_t i) {
assert(i<size());
return _buf[i];
}
const int& operator[](size_t i) const {
assert(i<size());
return _buf[i];
}
What is the different between the function? why I need the first one? and in which cases the first function will be work and in which cases the second function will be work?
On of those is const the other isnt. Let me put it in some context:
struct Foo{
int value = 0;
int& operator[](size_t i) {
std::cout << "non-const\n";
return value;
}
const int& operator[](size_t i) const {
std::cout << "const\n";
return value;
}
};
The const version will be called on const instances while the non-const will be called on non-const instances. E.g.
int main(){
Foo f;
int x = f[0];
f[0] = 3; // OK
const Foo g;
int x = g[0];
//g[0] = 3; // NOT OK
}
...will print
non-const
const
Indeed both methods should be the same and the major difference is the const version returning a const reference while the non-const returns a reference that allows to modify the value.
As you correctly observed, apart from the constness and the return type, the two are identical. To avoid duplicate code, sometimes it can make sense to use a small trick and write the const version in terms of the non-const:
const int& operator[](size_t i) const {
std::cout << "const\n";
return const_cast<Foo*>(this)->operator[](i);
}
See here for the full example.
Usually you don't want to let users change your objects somehow if they are marked as const.
It means that if you have a class which provides operator[], you don't want to let users change the internal state of objects of this class via operator[] if these objects are const.
That's why you have two overloads. If the object is const, then the version
const int& operator[](size_t i) const
is called. This version returns const int&, so you can't do any modification.
In opposite, if the object is not marked as const, then
int& operator[](size_t i)
is called and you are free to modify the internal state of the object via the reference returned.
The differences are the const keyword:
int& operator[](size_t i) { (1)
const int& operator[](size_t i) const { (2)
The first function return a reference to the object, which means that you can modify the object (for example by doing foo[0] = bar.
The second use the const keyword twice: const int& means that you return a const reference that you can't modify. The second const is here to specify that this function will not modify the object.
You need those two version because (1) is used when you want to modify an element of the collection and (2) is used on const object:
you can do this:
void foo(std::vector<int> const& v) {
int j = v[0];
}
because vector as an operator that look like (2)
The first overload states that the subscript operator can modify internals of the class instance, the later states that internals of the class instance are read-only and thus, can't be modified.
Effectively, it means that this pointer points to either const or non-const object.
Previously:
You tagged your question with C which is not correct, as C does not offer any class member functions and thus AFAIK, const after the global function declaration is illegal.
It means your class is providing the support for two things,
Non Const Object
Const Object
int& operator[](size_t i) will be called for Non const object, because there is no const qualifier at the end.
const int& operator[](size_t i) const will be called for const object, because there is const qualifier at the end.
I have this code:
template <class T>
class Something
{
T val;
public:
inline Something() : val() {}
inline Something(T v) : val(v) {}
inline T& get() const { return val; }
inline Something& operator =(const Something& a) { val = a.val; return *this; }
};
typedef Something<int> IntSomething;
typedef Something<const int> ConstIntSomething;
class Other
{
public:
IntSomething some_function()
{
return IntSomething(42);
}
ConstIntSomething some_function() const
{
return ConstIntSomething(42);
}
};
void wtf_func()
{
Other o;
ConstIntSomething s;
s = o.some_function();
}
However, the compiler picks the wrong overload of Other::some_function() in wtf_func() (i.e. the non-const one). How can I fix this? Note that for certain reasons I cannot change the name of Other::some_function().
o is not const-qualified, so the non-const some_function is selected. If you want to select the const-qualified overload, you need to add the const qualifier to o:
Other o;
Other const& oref(o);
ConstIntSomething s;
s = oref.some_function();
When overload resolution occurs, the compiler only looks at the o.some_function() subexpression; it does not look at the context around the function call to decide to pick something else. Further, the return type of a member function is not considered during overload resolution.
Note that it may make more sense for IntSomething to be implicitly convertible to ConstIntSomething, either using an operator ConstIntSomething() overload in IntSomething (less good) or using a non-explicit ConstIntSomething(IntSomething const&) constructor in ConstIntSomething (more good).
It doesn't pick the wrong overload; const-ness is resolved by whether this is const or not. In your case, o is non-const, so the non-const overload is picked.
You can hack this by creating a const-reference to o, e.g.:
const Other &o2 = o;
s = o2.some_function();
But really, you should probably be considering your overloads in Something. For instance, you can't currently do this:
IntSomething x;
ConstIntSomething y;
y = x;
which doesn't sound correct. Why shouldn't you be allowed to take a const ref to a non-const ref?
Your object o needs to be const object for a const function to be called on it. Otherwise the compiler rightly picks up the non const version of the function.
The compiler picks the overload to use based on the constness of the object that will become this. You can make it call the desired version with static_cast: s = static_cast<const Other&>(o.some_function());
You might also want to copy the new behaviour found in the containers of the C++0x standard library. Containers such as vector now have members cbegin() and cend() that return a const_iterator whether the container is const or not unlike begin() and end()
class Other {
// Rest of other
public:
// No overload for non-const
// Even if called with a non const Other, since this member is marked
// const, this will be of type Other const * in all cases and will call
// the const qualified overload of some_function.
ConstIntSomething csome_function() const
{
return some_function();
}
};
I define two versions of overloaded operator[] function in a class array. ptr is a pointer to first element of the array object.
int& array::operator[] (int sub) {
return ptr[sub];
}
and
int array::operator[] (int sub) const {
return ptr[sub];
}
Now, if I define a const object integer1 the second function can only be called..... but if I make a non-const object and then invoke as below:
cout << "3rd value is" << integer1[2];
which function is called here?
In your second example, the non-const version will be called, because no conversion is required, and a call that requires no conversion is a better match than one that requires a conversion.
Ultimately, however, you have a basic problem here: what you really want is behavior that changes depending on whether you're using your object as an rvalue or an lvalue, and const doesn't really do that. To make it work correctly, you normally want to return a proxy object, and overload operator= and operator T for the proxy object:
template <class T>
class myarray {
T *ptr;
class proxy {
T &val;
proxy &operator=(proxy const &p); // assignment not allowed.
public:
proxy(T &t) : val(t) {}
operator T() const { return val; }
proxy &operator=(T const&t) { val = t; return *this; }
};
proxy const operator[](int sub) const { return proxy(ptr[sub]); }
proxy operator[](int sub) { return proxy(ptr[sub]); }
// obviously other stuff like ctors needed.
};
Now we get sane behavior -- when/if our array<int> (or whatever type) is const, our operator[] const will be used, and it'll give a const proxy. Since its assignment operators are not const, attempting to use them will fail (won't compile).
OTOH, if the original array<int> was not const, we'll get a non-const proxy, in which case we can use both operator T and operator=, and be able to both read and write the value in the array<int>.
Your const version should return const int& not int, so that the semantics are just the same between the two functions.
Once you've done that, it doesn't matter which one is used. If the const version has to be used because your object has a const context, then it will be... and it won't matter as you're not trying to modify anything. Otherwise, it'll use the non-const version... but with just the same effect.