Re: Sanity check: public/private
Jack Klein wrote:
On 14 Sep 2006 19:57:17 -0400, Carlos Moreno
<moreno_at_mochima_dot_com@mailinator.com> wrote in
comp.lang.c++.moderated:
Say that I have a C++ program that consists only of
perfectly valid C++ code (in other words, the program
compiles and does not invoke undefined behaviour).
If I now replace every single instance of the keyword
private with the keyword public (and I change *nothing
else*), would the behaviour of my program change? That is,
in practical terms, should I expect the behaviour of my
program to change when compiled with an *actual* compiler
that is reasonably compliant and reasonably high-quality?
I would not expect the behavior to change.
class B
{
} ;
class D : private B
{
} ;
int
main()
{
try {
throw D() ;
} catch ( B const& ) {
return 0 ;
} catch ( D const& ) {
return 1 ;
}
return 2 ;
}
Or:
struct B
{
virtual ~B() {}
} ;
struct D : private B
{
B* myB() { return this ; }
} ;
int
main()
{
B* p1 = (new D)->myB() ;
D* p2 = dynamic_cast< D* >( p1 ) ;
return p2 == 0 ;
}
Compiling with -Dprivate=public results in a different return
value in each case. (It also results in a warning that the
second catch clause cannot be activated in the first example.)
As a corollary: if I simply add, at the beginning of the
file, the following line:
#define private public
I am pretty sure that using a macro to redefine a keyword is
undefined in C++, but I will admit that I couldn't find that
in a quick look at the standard.
It's not, as long as you don't include a standard header.
(That's why my two examples above depend on a difference in the
return code, rather than outputting something.) ?17.4.3.1.1/2:
"A translation unit that includes a header shall not contain any
macros that define names declared or defined in that header.
Nor shall such a translation unit define macros for names
lexically identical to keywords." (I think that the first
sentence is rather weak. It suggests that "#define allocator
42" would be legal before including <vector>, since allocator
isn't defined in <vector>, but in <memory>. But obviously,
<vector> is going to include <memory>.)
Why should defining a macro to change a keyword be a problem
otherwise?
But let's assume it does not, or your implementation
ignores it.
And change *nothing else*, would I expect the behaviour of
the program to change?
The behavior of the program should not change for any reason
that I can think of.
See above. It does. (At least with g++, but I'm pretty sure
that it is conformant here.)
[...]
An object containing different access types may be laid out in
an implementation-defined manner. Changing the access
specifiers may cause the implementation to change the ordering
of the members. This would likely cause the machine code to
change, as some instructions might well include the offset in
an address or as an index to a pointer.
This could also cause a change in behavior. Imagine a compiler
which always places private members first, and otherwise
respected the order of declaration. Then, given:
struct A
{
int a;
private:
int b;
}
A anA ;
if ( &anA.a > &anA.b ) //...
In this case, of course, the code has unspecified behavior to
begin with, and so the change falls within a much larger set of
possible changes. In theory, at least, a compiler could change
the order of evaluation in an expression according to whether
elements were private or public; if the observable behavior of
the program depended on such ordering, it would change.
I don't think that this was what Carlos had in mind, but it is
certainly clear that in any program which has several possible
legal behaviors, changing private to public could potentially
change the behavior.
In practice, I don't know of a compiler where this would be the
case (but the behavior may change for other reasons, e.g.
different optimization options).
The answer that my mind gives me is: not sure about the
machine code; but for the behaviour of the prorgam: no, it
does not change -- I can't think of any reason why it could
change; but never say never, and I'm sure with the armada
of experts and gurus out there, if there is any such reason,
I will find out :-)
If necessary, please divide the answer into the following
two cases:
1) private is only used as class-member access specifier
I think that it was once an expressed goal that changing private
to public here would make no difference in the specified
observable behavior of a program. As pointed out above, it's
rather obvious that it is allowed to make a difference when more
than one behavior is acceptable, i.e. the order of evaluation in
an expression---such differences may occur even without any
change to the code; differences due to data layout are
explicitly possible as well, beyond the ones normally possible,
but these, too, are due to differences allowed in the data
layout only in the case where some of the data is private.
2) private is also used for inheritance.
There are definite, explicit and required differences here, as
shown above.
(I believe the answer NO is valid for both cases, but I'm
mostly interested in case (1), so if the answer is
different, please specify the reasoning for both cases).
My vote is: behavior no; binary image maybe.
The actual examples outvote you, two to one:-).
--
James Kanze GABI Software
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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]