In the example above, how do I know which func I'm calling? More to the point, how do I call the one with the const?Code:class Foo
{
Foo() { }
int func(int a)
{ return 0; }
int func(int a) const
{ return 1; }
}
int main()
{
Foo foo;
foo.func();
}
Printable View
In the example above, how do I know which func I'm calling? More to the point, how do I call the one with the const?Code:class Foo
{
Foo() { }
int func(int a)
{ return 0; }
int func(int a) const
{ return 1; }
}
int main()
{
Foo foo;
foo.func();
}
#include <iostream>
#include <string>
using namespace std;
class Foo
{
public:
Foo() { }
int func(int a)
{ cout << a++ << endl; return 0; }
int func(int a) const
{ cout << --a << endl;return 1; }
};
int main()
{
int i = 10;
Foo foo;
foo.func(i);
Foo const foo1;
foo1.func(i);
}
A const object will call const functions. A non-const object will call non-const functions.Quote:
Originally Posted by ecspansion
But more about your real question -- how do you call the one with const. In general, you should not worry about this. If a function has both a const and a non-const overload, they should perform the same action. Usually this means that the const overload will return a const-reference to some internal variable while the non-const overload will return a non-const reference to the same variable. It would be a very poor design for the two overloads to perform different types of actions.
I hope this makes sense.
- Kevin
Probably why they didn't implement std::map with a const-overload for operator[]. Not because it couldn't find anything to return when the item doesn't exist, it could return a const reference to a default of the the second value (i.e. T()) or even a copy of one, but because operator[] when non-const has the side-effect of inserting when the element is not found.
Thus
And you will probably find that m[5] exists (and will be an empty string).Code:#include <map>
#include <string>
int main()
{
std::map< int, std::string > m;
m[1] = "hello";
m[4] = "world";
std::cout << m[1] << ' ' << m[4] << ' ' << m[5] << '\n';
if ( m.find( 5 ) != m.end() )
{
std::cout << "m[5] exists\n";
}
else
{
std::cout << "m[5] does not exist\n";
}
}
Note that the non-const overload is always called in preference if possible.
If you want to specifically call the const version for a non-const object use
const_cast works as well of course but the"style" guideline of most (authors) is to use static_cast to add const-ness.Code:static_cast<const Foo&>(foo).func(1);
Generally bad design if you have to do that. If I did decide to I'd probably get a const reference to point to the non-const instance and call it from the const-reference.
Thus:
Code:Foo foo;
const Foo& foocref( foo );
foocref.method(); // will call const overload
Of course, it is better to use static_cast, because static_cast can only add const specifiers. It is not dangerous.Quote:
Originally Posted by freddyflintstone
const_cast can remove const specifier, and should be avoided if possible (but it cannot be always avoided, for example when linking with libraries which don't use const specifiers).
If both the const and non-const functions do the same thing as Keven said, what difference does it make which one get called? The calling function shouldn't care because the result is the same either way (except of course for the const modifier).
Well of course you and I wouldn't design a class where you'd want to explicitly call a const-overload, but maybe we're using someone else's badly designed class (and can't change it).Quote:
Originally Posted by stober
Now we're discussing which is the best way to work around it (i.e. create a const reference or cast).
Bad design sure but the above 2 methods just answers the question. Here's another way to force a call to the const onverload. Its even more reprehensible.Quote:
Originally Posted by NMTop40
Code:int (Foo::*f)() const = &Foo::func;
(foo.*f)(0);
You guys have spent a lot of time explaining the work-arounds for a poorly written library. While I understand the desire to work-around something poorly designed, and calling a const-method from a non-const variable is "safe", the next question I worry, will be the other way around: "How do I call a non-const method if I have a const-variable?" This is not safe and leads to undefined behavior. If today you have a need today to go one way, you'll have the need tomorrow to go the other, and then you're in the realm of undefined behavior. Very, very scary!!!
I have seen libraries where const was never used, and that required const_cast's to remove const-ness. This made me very nervous, but I could understand that perhaps this was someone (or some group) who just hadn't learned the value of const, and hope that at least that the code underneath was consistent and would not violate assumed const-ness.
But to have a library that has both const and non-const methods and where the methods do different things, that scares me a LOT because then it indicates that the library designers didn't have a consistent idea about what the library was supposed to do. It also may indicate that the library designers can't communicate with eachother. It will lead to maintenance nightmares in the future for both me as a user and the library designers themselves. Personally, if I had any say in the matter, I'd stay clear of any library where the const and non-const methods differed in what they were supposed to do.
I REALLY hope that the OP was more of an accademic question rather than something he is being forced to deal with.
I don't see anything wrong with having two function declarations differing only in their constness. And obviously the developers of the C++ language didn't either, or else they would have chosen to decorate the names the same.Quote:
But to have a library that has both const and non-const methods and where the methods do different things, that scares me a LOT because then it indicates that the library designers didn't have a consistent idea about what the library was supposed to do.
To me, you're simply saying that one function will modify member data, whereas the other won't. Casting aside, a const object will call the const member function while a non-const object will call the non-const member function. Sounds perfect to me.
As for the poster's question -- you know by the constness of your object. And as KevinHall said, if you have to resort to casts to call the other function, then you need to redesign.
Bond, you misinterpreted my post. I agree with what you said (please see my first post in this thread).
If someone needs to cast an object so he can call a method of different const-ness, then this implies that the const and non-const methods do something functionally different; and this is what scares me. For example:
This is obviously poor design, and something I would want to avoid! I hope this clears up any confusion about what I said. :DCode:class Foo
{
public:
double MathOperation(double x)
{
return x*x;
}
double MathOperation(double x) const
{
return sqrt(x);
}
};
Thanks for the responses everyone.
I don't believe the library to be designed poorly, the designers just wanted different behavior for different objects - in this case, both funcs return the same data. I'm using this func on data that must be modified before using it, but shouldn't be changed by the function so some sort of a cast or const pointer/reference is required.
hmmm... I suppose it would have been more clear if the functions had different names & therefore could be called explicitly w/o casts.
Thanks again.
If there is a const member with the same name that a non-const member, since the two functions must be functionally identical, the non-const member function must not modify the object (but may cache some informations, or, for a monothread application, may modify the object data during the processing, and restore it before returning). For the programmer they behaves exactly the same, even if the non-const function may do some optimizations (very rarely, i mainly think to put a temporary null terminator in a string when parsing it).Quote:
Originally Posted by ecspansion
In fact, writing two functions having the same name, one const, the other non-const, is generally used to return references or pointers which have the same attributes, and the assembly code is basically exactly the same.
So, don't matter which function is called, the contract of these two functions is exactly the same. If that is not the case, it signs a design flaw.
To correct this design flaw, you should change the name of these member functions (at least one, maybe the two functions, since their names don't say what they do).
This should explain why it is not a proper style.Quote:
So, don't matter which function is called, the contract of these two functions is exactly the same. If that is not the case, it signs a design flaw.
Also remember that sometimes using function like operator= etc may result in undesired behaviour if both of the functions (const and non const) have different codes.