19

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() */
}
1
  • Why would this fail? C++ allows conversion from non-const to const, vis a vis function parameter. Commented Jul 29, 2009 at 16:02

2 Answers 2

15

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?

Sign up to request clarification or add additional context in comments.

4 Comments

A hidden class would be my best bet - like using a Node struct inside a larger class.
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).
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.
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... :(
6

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;

3 Comments

I think I'd prefer const_cast<const A&>(a1).a(). It would seem a bit safer.
Yes, that is the best way to do it if you're going to use a cast. I don't think it's any safer than the second method, though, the compiler will enforce full type safety for the assignment to the reference. Anyway, I figured you would implement this by, for example, changing method signatures from A& to A const& when you are passing these things around, rather than directly manipulating them as in this obviously contrived example.
I don't understand why the answer of Charles Bailey has such higher voting than this (IMHO correct and working) answer of Tim Sylvester which shows the opposite of There is no way "to make this work". Actually, I came here because I knew that I solved such problem somewhere in my code but I forgot where and how. (Btw. I solved it exactly as described above. May be, I should try to google on my own local source code next time...)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.