Click here to Skip to main content
11,494,407 members (65,864 online)
Rate this: bad
Please Sign up or sign in to vote.
See more: C++
i recently observed that it is possible for a class having two functions with same name and same prototype which differs only in const-ness

class A
void PrintMessage()
  printf("void PrintMessage()");
void PrintMessage() const
  printf("void PrintMessage() const");


A a;
a.PrintMessage();  ///Here function without const get called 

My question is , how to call function with const ??
Posted 10-Jan-13 21:25pm
Sergey Alexandrovich Kryukov at 11-Jan-13 3:23am
As I say, my 5 for the question.
Rate this: bad
Please Sign up or sign in to vote.

Solution 1

The const method will be called on const object of the class. So to call the const method:

const A a;
Sergey Alexandrovich Kryukov at 11-Jan-13 3:32am
This is true. My 5, but I think this is a very bad feature of the language (not sure it it is described in the standard; do you know that?). I tried to explain it in my answer and warn OP. Yes, I do understand that my criticism is pretty much useless...
Rahul Rajat Singh at 11-Jan-13 3:36am
This ia actually a documented behavior. In fact Scott Mayer's book Effective C++ has an Item (I think it was #3) specially dedicated to logical constness and bitwise constness.

But again, I was into C++ a long time ago so perhaps my explanation was little vague too. But i have to agree with you that C++ has many dangerous features and one should use a feature only when he/she fully understands it.
Sergey Alexandrovich Kryukov at 11-Jan-13 3:44am
OK, thank you very much for the clarification. No, your explanation is absolutely clear to me. (I'm also into it for many years, but maybe in different ways — very many languages...)

All my considerations are about the rational of it. Don't you see how it's wrong, in this particular case? It would be much simpler to cut out all pathologies, especially if there is no use of them. (Again, as I said before, constant modifiers are very useful.)

Rahul Rajat Singh at 11-Jan-13 3:51am
agreed. it is definitely wrong. The bottom line should be "We should use language features to facilitate better design. We should not just use something just because it is the part of the language and we could use it"
Sergey Alexandrovich Kryukov at 11-Jan-13 11:22am
That is certainly a very important point, but not the only lesson learned. To me, it's a more of a lesson about how a programming language should look like, to fulfill its purpose.
Thank you for interesting discussions and help.
PrafullaVedante at 11-Jan-13 3:40am
Thanks Rahul for the answer :)
Rate this: bad
Please Sign up or sign in to vote.

Solution 2

First of all, const in this context simply means that the state of the object should not be modified by the call. Apparently, it makes sense only for instance (non-static) functions.

I took interest in this pathology and experimented. My Microsoft compiler compiled it, even with the call, to my surprise. I expected that the class declaration will compile, but an attempt to call the method will not. I was wrong.

Now, debugging shows that the non-constant function is always called for non-constant object and a constant function for a constant object.

To me, it makes no sense at all; and the only reasonable behavior would be to fail compilation. Perhaps, you managed to find a weakness in the standard ([EDIT] Rahul confirmed that this is described in the standard; thank you, Rahul). Here is the problem with that: if an instance of the class in non-constant, the constant function is still successfully called, quite naturally. But if you don't change anything at all but only add a non-constant function with the same name/signature, it "steals" the call to itself. I think such compiler behavior is very dangerous. (However, C++ has so many dangerous features, that this one is just yet another small one.)

Anyway, in practice, I would recommend you to avoid this situation by all means. C++ requires some discipline...

May be so called C++ layers can find some excuse for that, I don't know. Anyway, I would gladly consider such arguments.

And I don't care too much: I never had any faith in C++, in my opinion, it brought a lot more harm to programming and culture then benefits. (Please, C++ advocates, no flame wars... not really interesting; this is my personal opinion which I am not going to discuss much...)

But I'm going to vote 5 for this question!

Rahul Rajat Singh at 11-Jan-13 3:27am
The const object is calling the const method. I checked it on my VC++ 8 compiler.

The const keyword in C++ is to show that this function will not change the internal state of the class. this keyword will enforce the bitwise constness of the object. using the overload on const would mean that all the non const objects will call the non const version of the function and all the const objects will call the const method.
Sergey Alexandrovich Kryukov at 11-Jan-13 3:34am
I know. Didn't you see that I said the same? The problem is different.

Of course you cannot call a non-constant function on a constant instance; this is quite reasonable. The problem that you can call both on a non-constant instance. Having two identical (by constness) functions create a subtle ambiguity and even the "switch" to a different call when you add another method. I perfectly understand the logic behind this behavior, I only consider this as a deadly sin of the language design...

I checked it, too, and can understand the logic. Maybe, you did not see my updated answer where I explain some "anti-rationale" for this behavior. Const modifier itself if very useful thing, but in this pathological case it plays a dangerous role. Not the modifier itself but the switch of the call.
Rahul Rajat Singh at 11-Jan-13 3:39am
Totally agreed. And I was actually supporting your answer by putting in the bit about bitwise constness(before you updated the answer) and not cribbing about it.

Perhaps I need to start using better(read girly) words :)
Sergey Alexandrovich Kryukov at 11-Jan-13 3:45am
Very good, thank you.
PrafullaVedante at 11-Jan-13 3:41am
Sergey Alexandrovich Kryukov,I am totally agree with you.
Sergey Alexandrovich Kryukov at 11-Jan-13 3:46am
And thank you for the finding and asking this pretty interesting question.
Rate this: bad
Please Sign up or sign in to vote.

Solution 3

The technical reason behind this behaviour is the the overload resolution.
Method declared as
class A {
  void PrintMessage()       { ... }
  void PrintMessage() const { ... }
translate behind the scenes to (this is conceptual, you can not see or call that):
static void A::PrintMessage(A       * const this) { ... }
static void A::PrintMessage(A const * const this) { ... }
If the C++ compiler has to choose between function declarations, the overload resolution takes the best match:
A varA = A();
const A constA = A(); // BTW: this is identical to A const constA = ...
this translates internally behind the scenes again into:
A::PrintMessage(&varA);   // best match for &varA of type A* is PrintMessage(A*const)
A::PrintMessage(&constA); // best match for &constA of type A const* is PrintMessage(A const*const)
From a technical point of view: straight forward - no (other) magic involved Wink | ;-)
PrafullaVedante at 11-Jan-13 14:18pm
Ammmm ..... Do you mean that following is also allowed ??

void A::PrintMessage(int i ) { ... }
void A::PrintMessage(const int i ) { ... }

//If you compile above code .... you will get compilation error
lewax00 at 11-Jan-13 16:33pm
That's slightly different. If you use pointers to ints instead it will work (I'm pretty sure anyways).
Andreas Gieriet at 11-Jan-13 19:07pm
All const-ness on the right of the last pointer/reference sign of a parameter type is ignored, all on the left of the last pointer/reference sign of the parameter type is relevant.

See C++, 245pp (Overload).
[...] Parameter declarations that differ only in the presence or absence of const and/or volatile are equivalent. That is, the const and volatile type-specifiers for each parameter type are ignored when determining which function
is being declared, defined, or called. [...] Only the const and volatile type-specifiers at the outermost level of the parameter type specification are ignored in this fashion; const and volatile type-specifiers buried within a parameter type specification are significant and can be used to distinguish overloaded function declarations. In particular, for any type T, “pointer to T,” “pointer to const T,” and “pointer to volatile T” are considered distinct parameter types, as are “reference to T,” “reference to const T,” and “reference to volatile T.” [...]

The term "outermost" is to be read in a parameter declaration from right to left: the first occurance of const before a pointer or reference (or none in the absence of one for these) is ignored (i.e. treated as identical type with respect to overloading).

It basically says:
- a parameter type T is identical to T const
- a parameter type T is identical to const T

- a parameter type T* is distinct to T const *
- a parameter type T* is distinct to const T *

- a parameter type T& is distinct to T const &
- a parameter type T& is distinct to const T &

Therefore, void F(int i); and void F(const int k); are identical.
Where as void F(int& i); and void F(const int& k); are distinct.
Likewise void F(int* i); and void F(const int* k); are distinct.

And void F(int& i); and void F(int& const k); are identical.
Likewise void F(int* i); and void F(int* const k); are identical.

Andreas Gieriet at 11-Jan-13 19:26pm
BTW: Overloading easily fools you, not only in C++. In all languages with overload machinery, I experienced troubles in the sense that this is not made for humens to memorize:
- what exactly is part of the signature with respect to the overloading resolution
- what is "best match"
- constness
- volatile
- implicit number promotions
- implicit conversions
- user defined conversions
- default parameters
- named parameters
- scope hiding
- ...
This is a complicated but defined decision tree.

Best is to avoid overload situation whenever possible (or master the decision tree ;-))


This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 Dnyaneshwar@Pune 740
1 Sergey Alexandrovich Kryukov 443
2 CHill60 350
3 Nakul Chaudhari 236
4 OriginalGriff 221
0 Sergey Alexandrovich Kryukov 10,277
1 OriginalGriff 8,805
2 Sascha Lefèvre 3,704
3 Maciej Los 3,392
4 Richard Deeming 2,500

Advertise | Privacy | Mobile
Web04 | 2.8.150520.1 | Last Updated 11 Jan 2013
Copyright © CodeProject, 1999-2015
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100