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! ]
> 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
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
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
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
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 ]
> 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
[...]
> 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
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.