Click here to Skip to main content
15,881,882 members
Please Sign up or sign in to vote.
4.75/5 (4 votes)
See more:
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

C++
class A
{

public:

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
Comments
Sergey Alexandrovich Kryukov 11-Jan-13 3:23am    
As I say, my 5 for the question.
—SA

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

C++
const A a;
a.PrintMessage();
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 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...
—SA
Rahul Rajat Singh 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 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.)

Cheers,
—SA
Rahul Rajat Singh 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 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.
—SA
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!

—SA
 
Share this answer
 
v4
Comments
Rahul Rajat Singh 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 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.
—SA
Rahul Rajat Singh 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 11-Jan-13 3:45am    
Very good, thank you.
—SA
PrafullaVedante 11-Jan-13 3:41am    
Sergey Alexandrovich Kryukov,I am totally agree with you.
The technical reason behind this behaviour is the the overload resolution.
Method declared as
C++
class A {
  void PrintMessage()       { ... }
  void PrintMessage() const { ... }
}

translate behind the scenes to (this is conceptual, you can not see or call that):
C++
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:
C++
A varA = A();
varA.PrintMessage();
const A constA = A(); // BTW: this is identical to A const constA = ...
constA.PrintMessage();

this translates internally behind the scenes again into:
C++
...
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 ;-)
Cheers
Andi
 
Share this answer
 
v3
Comments
PrafullaVedante 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 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 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.

Cheers
Andi
Andreas Gieriet 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 ;-))

Cheers
Andi

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900