C++/error C2678(c++)
Expert: Ralph McArdell - 3/5/2006
QuestionDear Mr McArdell
Through search engine online, I found your response for the question about error c2228. I managed to followed it and appreciated your clear explaination with comprehensive examples.
With reference online, I have found the fix for the above error using const modifier for a function as follows (without explaination). I hence would like to understand better about const modifier for function, particularly this case which the error was generated.
/*
I am using c++ MS studio 6.
Task is a struct with member data of type int called prio.
*/
bool operator<(const Task& obj) const{
return prio<obj.prio;
}
I thought const modifier for function is optional, at least previously no error was generated in similar case. My understanding of this modifier is to restrict the changes to object being passed in. Please clarify.
Thank you for your time.
LingPei
AnswerFirst let me clarify errors. C2678 is _not_ a C++ error - the C++ standard stipulates where an implementation should determine that code is in error, but does not say what form of reporting errors takes. C2678 is an error specific to your compiler - MSVC++ 6.
Second, you do not say what the error is. I assume it is the same as that documented in an MSDN library I have available:
"binary 'operator' : no operator defined which takes
a left-hand operand of type 'type' (or there is no
acceptable conversion)"
Third, you do not say what piece of code the compiler raised this error for. Was it referring to the < in the operator< you show (prio<obj.prio)? If so then the type of member prio has no operator< defined that can be used for the comparison.
This rather limits the specific help I can give you.
So, to the meaning of const when applied to instance member (and only class/struct instance member) functions; yes it is optional. However if you do not change the state of the object it is a good idea to specify the member function const. Such member functions can then be used by objects of the type that are const. What it actually does is make the this pointer const so that it cannot (easily) be used to modify class instance member data or call non-const instance functions. For a class X the type of the this pointer for an instance member function declared const will be const X * (or X const *). Similar rules apply for instance member functions declared volatile or const volatile.
An instance member function has, in all C++ implementation I know of, a hidden this parameter added by the compiler thus:
class X { InstanceFn(); }; --> class X { InstanceFn(X * this); };
I have shown the minimum to get the point across. In fact the compiler generates a stand alone function whose name is mangled to include all the information required to identify the function as being the specific member function of class X:
class X { InstanceFn(); }; --> X_InstanceFn(X * this);
I have not bothered with what the compiler generates for the rest of class X as it is not relevant to our discussion. The above example uses a very simple name mangling scheme - real name mangling schemes are more complex - see the material at
http://www.codesourcery.com/cxx-abi/abi.html section 5.1 for an example.
Now let us consider an instance member function declared const. The transformation can be considered thus:
class X { ConstInstanceFn() const; };
--> X_ConstInstanceFn(const X * this);
Note that in this case the compiler makes the type of the this pointer const X *.
As far as making a call to an instance member function goes:
X x;
x.InstanceFn() --> X_InstanceFn( &x );
Note that here the instance context (x) is maintained by having &x passed into the function as the this pointer. Now consider a similar example:
const X x;
x.InstanceFn() --> X_InstanceFn( &x );
This is identical to the previous example except that x is now const. The effect is an error as X_InstanceFn takes a pointer to a non-const X as its this parameter. This is because the declaration of InstanceFn in the class X definition did not specify that it was a const member function.
However, if we call ConstInstanceFn instead then we get no error:
X x;
x.ConstInstanceFn() --> X_ConstInstanceFn( &x );
and
const X x;
x.ConstInstanceFn() --> X_ConstInstanceFn( &x );
In this case as ConstInstFunction was declared to be a const member function the this parameter of the generated X_ConstInstanceFn will be const X * and so can called with values that are X * or const X *.
Note that the above example code snippets are for example and understanding the points being made only. I have not tried compiling them so sorry for any typos.