Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

overload resolution before access checking

10 views
Skip to first unread message

Walter Bright

unread,
Jul 8, 2006, 7:25:25 PM7/8/06
to
Given:
-----------------
struct S
{
public:
void foo(long);
private:
void foo(int);
};
....
S s;
s.foo(1); // error, S::foo(int) is private
------------------

In other words, overload resolution happens before access checking. If
it happened after access checking, then S::foo(long) would have been
selected.

What is the rationale for this behavior (which has been in C++ since at
least 1986)? Shouldn't private members be invisible rather than
inaccessible?

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Jack Klein

unread,
Jul 9, 2006, 10:28:34 AM7/9/06
to
On 8 Jul 2006 19:25:25 -0400, Walter Bright
<wal...@digitalmars-nospamm.com> wrote in comp.lang.c++.moderated:

> Given:
> -----------------
> struct S
> {
> public:
> void foo(long);
> private:
> void foo(int);
> };
> ....
> S s;
> s.foo(1); // error, S::foo(int) is private
> ------------------
>
> In other words, overload resolution happens before access checking. If
> it happened after access checking, then S::foo(long) would have been
> selected.
>
> What is the rationale for this behavior (which has been in C++ since at
> least 1986)? Shouldn't private members be invisible rather than
> inaccessible?

The rationales for choices made in the standard are better discussed
in comp.std.c. At a reasonably educated guess, however, I would say
because it would greatly complicate compilers to do things the way you
want, and would produce less useful error messages as well.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

James Dennett

unread,
Jul 9, 2006, 10:26:25 AM7/9/06
to
Walter Bright wrote:
> Given:
> -----------------
> struct S
> {
> public:
> void foo(long);
> private:
> void foo(int);
> };
> ....
> S s;
> s.foo(1); // error, S::foo(int) is private
> ------------------
>
> In other words, overload resolution happens before access checking. If
> it happened after access checking, then S::foo(long) would have been
> selected.

Unless this code was in a member function of S, in which case
S::foo(int) would have been selected and called.

> What is the rationale for this behavior (which has been in C++ since at
> least 1986)? Shouldn't private members be invisible rather than
> inaccessible?

There seem to be rough guidelines that providing additional
access should not change the meaning of code, including not
making valid code invalid. In simple cases that's still
true. If prefers a diagnostic to a subtle, silent change;
there's little chance that code as you showed above is
deliberate, and code using that class would behave
differently depending on where it was if the private
members were invisible from outside of the class.

It can be useful to have private members being visible but
inaccessible, for example to "poison" certain operations
so that they can't be inadvertently used.

Diverting slightly: what would it even mean to have an
invisible private copy constructor? The compiler wouldn't
synthesize one, as one has been declared, but code outside
the class can't call it if it's invisible... so would we
have a brand new case where no copy constructor was found
at all?

I think C++'s rules that access checking is done late are
somewhat counter-intuitive, but providing some robustness
and are straightforward once understood. In other languages
(say Java), there are unpleasant interactions between
overloading, overriding and access control (for example,
a class can't privately implement an interface, which
rules out one useful technique for giving different
clients of the class access to only the interface they
need).

-- James

Falk Tannhäuser

unread,
Jul 9, 2006, 5:00:30 PM7/9/06
to
Walter Bright wrote:
> struct S
> {
> public:
> void foo(long);
> private:
> void foo(int);
> };
> ....
> S s;
> s.foo(1); // error, S::foo(int) is private
[...]

> What is the rationale for this behavior (which has been in C++ since at
> least 1986)? Shouldn't private members be invisible rather than
> inaccessible?

The design goal was that, as long as the code remains well-formed,
changing a member's access level shall not change the semantics
of the program.

Falk

Walter Bright

unread,
Jul 9, 2006, 5:11:59 PM7/9/06
to
James Dennett wrote:
> Unless this code was in a member function of S, in which case
> S::foo(int) would have been selected and called.

Right, there would be different behaviors depending on the context in
which foo() is invoked.

>> What is the rationale for this behavior (which has been in C++ since at
>> least 1986)? Shouldn't private members be invisible rather than
>> inaccessible?
>
> There seem to be rough guidelines that providing additional
> access should not change the meaning of code, including not
> making valid code invalid. In simple cases that's still
> true. If prefers a diagnostic to a subtle, silent change;
> there's little chance that code as you showed above is
> deliberate, and code using that class would behave
> differently depending on where it was if the private
> members were invisible from outside of the class.

That is as I suspected, but I am wondering if I am missing something
more significant.


> It can be useful to have private members being visible but
> inaccessible, for example to "poison" certain operations
> so that they can't be inadvertently used.

Ok. It would prevent, for example, the compiler passing over it and
using a base class operation instead.


> Diverting slightly: what would it even mean to have an
> invisible private copy constructor? The compiler wouldn't
> synthesize one, as one has been declared, but code outside
> the class can't call it if it's invisible... so would we
> have a brand new case where no copy constructor was found
> at all?

It is hard to see what the ripple effect of this might be.

> I think C++'s rules that access checking is done late are
> somewhat counter-intuitive, but providing some robustness
> and are straightforward once understood. In other languages
> (say Java), there are unpleasant interactions between
> overloading, overriding and access control (for example,
> a class can't privately implement an interface, which
> rules out one useful technique for giving different
> clients of the class access to only the interface they
> need).

Are private members invisible in Java? I agree that the subtlety
interactions between all these features can be difficult to predict in
advance.

-Walter Bright
www.digitalmars.com C, C++, D programming language compilers

Walter Bright

unread,
Jul 9, 2006, 5:12:20 PM7/9/06
to
Jack Klein wrote:
>> What is the rationale for this behavior (which has been in C++ since at
>> least 1986)? Shouldn't private members be invisible rather than
>> inaccessible?
>
> The rationales for choices made in the standard are better discussed
> in comp.std.c.

I thought it would be better here, as the choice predates the standard
by over a decade, and there's no possible way it could be changed.

> At a reasonably educated guess, however, I would say
> because it would greatly complicate compilers to do things the way you
> want, and would produce less useful error messages as well.

I am not suggesting that I want this to change. I am simply trying to
understand the rationale behind it.

I agree it would be harder to implement, but implementation difficulty
doesn't seem to have ever been a factor - C++ is the hardest language to
implement, by far <g>. Poor error messages have also plagued C++ because
of lack of redundancy in the syntax, but I'm not convinced that the
different access mechanism would make things better or worse.

-Walter Bright
www.digitalmars.com C, C++, D programming language compilers

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

David Abrahams

unread,
Jul 9, 2006, 6:12:47 PM7/9/06
to
Walter Bright <wal...@digitalmars-nospamm.com> writes:

> Given:
> -----------------
> struct S
> {
> public:
> void foo(long);
> private:
> void foo(int);
> };
> ....
> S s;
> s.foo(1); // error, S::foo(int) is private
> ------------------
>
> In other words, overload resolution happens before access checking. If
> it happened after access checking, then S::foo(long) would have been
> selected.
>
> What is the rationale for this behavior (which has been in C++ since at
> least 1986)? Shouldn't private members be invisible rather than
> inaccessible?

I'm pretty sure I read the answer to this (like most other C++
rationale questions) in D&E.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

James Kanze

unread,
Jul 10, 2006, 5:28:16 PM7/10/06
to
Walter Bright wrote:

[...]


> Are private members invisible in Java?

Yes. In addition, they are implicitly final.

> I agree that the subtlety interactions between all these
> features can be difficult to predict in advance.

I don't think that there's a perfect solution. I find the C++
solution rather robust, and don't have problems with it, but
that doesn't mean that other solutions are necessarily wrong.

--
James Kanze kanze...@neuf.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Dave Harris

unread,
Jul 10, 2006, 5:38:54 PM7/10/06
to
wal...@digitalmars-nospamm.com (Walter Bright) wrote (abridged):

> In other words, overload resolution happens before access checking. If
> it happened after access checking, then S::foo(long) would have been
> selected.
>
> What is the rationale for this behavior

There is none.

In Stroustrup's D&E book he says he can't remember, but he thinks it just
fell out of the way the first parser was written without being consciously
chosen. It does mean that access control does not affect the semantics of
a program, only whether it compiles, but that wasn't the motivation for
it.


> Shouldn't private members be invisible rather than inaccessible?

In any case, they are visible to the virtual dispatch mechanism.

#include "base.h"

class Derived : public Base {
private:
void dontCallMe() const;
};

Here Derived::dontCallMe() can in fact be called if the base class is
like:

class Base {
public:
virtual void dontCallMe() const;
}

The private Derived function overrides the public, virtual Base one even
though it is not itself declared virtual. This is one of the reasons
inheritance remains a dangerous, tightly-coupled relationship in C++.

-- Dave Harris, Nottingham, UK.

0 new messages