views:

236

answers:

2

I am trying to create a class with two methods with the same name, used to access a private member. One method is public and const qualified, the other is private and non-const (used by a friend class to modify the member by way of return-by-reference).

Unfortunately, I am receiving compiling errors (using g++ 4.3): When using a non-const object to call the method, g++ complains that the non-const version of my method is private, even though a public (const) version exists.

This seems strange, because if the private non-const version does not exist, everything compiles fine.

Is there any way to make this work? Does it compile on other compilers?

Thanks.

Example:

class A
{
public:
    A( int a = 0 ) : a_(a) {}
public:
    int   a() const { return a_; }
private:
    int & a()       { return a_; } /* Comment this out, everything works fine */
    friend class B;
private:
    int a_;
};


int main()
{
    A       a1;
    A const a2;

    cout << a1.a() << endl; /* not fine: tries to use the non-const (private) version of a() and fails  */
    cout << a2.a() << endl; /* fine: uses the const version of a() */
}
+9  A: 

Overload resolution happens before access checking, so when you call the a method on a non-const A, the non-const member is chosen as a better match. The compiler then fails due to the access check.

There is no way to "make this work", my recommendation would be to rename the private function. Is there any need to have a private accessor?

Charles Bailey
A hidden class would be my best bet - like using a Node struct inside a larger class.
Hooked
Thats too bad. I suspected this would be the case, but I don't see why it has to be. Hopefully someone will show me why it needs to be, so I can rest easily.The reason I want this behavior is because I usually write my getters and setters as two const/non-const version of the same method, without the "get"/"set" prefix. For this particular class, I do not want to allow any class except one to use the setters (hence the friend class declaration).
michalmocny
The ability to overload function is primarily useful when the functions perform the same, or similar, logical operation but on a different type of argument (especially useful in writing generic code in templates). Retrieving the value of something is a different operation from obtaining a reference to something in order to update it. For this reason it makes sense (to me at least!) to give the functions different names. I think you're 'swimming against the stream' if you try and keep the same names.
Charles Bailey
Interesting way to look at it.However, I have always looked at it differently, for example:stl containers have a begin()/end() members which return iterator or const_iterator depending on the object cv qualification automatically (Yes, c++0x is adding cbegin()/cend() to explicitly request const version even when object is non_const, particularly useful when using auto keyword).I would consider this situation to be exactly the same, I happen to be return a reference in this example, but it could have been a const/non const pointer.If the function was not private all would be fine... :(
michalmocny
+1  A: 

It will only select the const version if the object is declared is const, otherwise it will select the non-const version (even if that results in an error).

This should work:

cout << ((const A*)&a1)->a() << endl;

or this:

A const& ra1 = a1;
cout << ra1.a() << endl;
Tim Sylvester
Charles Bailey
Tim Sylvester