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?
As a corollary: if I simply add, at the beginning of the
file, the following line:
#define private public
And change *nothing else*, would I expect the behaviour of
the program to change?
As a corollary of the corollary, how about using the compiler
switch -Dprivate="public" to introduce the #defined symbol
without touching the source code? (I guess this is exactly
the same as the previous case, right?)
In all of the above: should I expect the generated machine
code to change? (assuming all the compiler switches and
optimization settings are exactly the same)
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
2) private is also used for inheritance.
(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).
Thanks for any comments,
Carlos
--
PS: Reasons why I'm asking this could be provided upon
request -- it's just that this post is already long
enough.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
According to the holly standard, the memory layout
for variables separated by different access specifiers
is implementation issue. Therefore if you change
private to public, the member layout maybe different.
> 2) private is also used for inheritance.
>
For following example,
struct B
{
int t;
};
struct D1 : private B // private inheritance (hold-a)
{
D1(){ t = 0; }
};
struct D2 : public D1
{
D2(){ t = 0; } // error, B::t is not accessible.
};
So, again private and public make difference here.
Someone could use above behavior to implement
compile-time checking/assertion, maybe.
> (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).
>
Actually I do not known any compilers really treat
private and public member differently, because
access specifiers are purely logical constructs.
But I do not have a good reason to do such a
replacement. :-)
>
> 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.
> 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. 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.
> As a corollary of the corollary, how about using the compiler
> switch -Dprivate="public" to introduce the #defined symbol
> without touching the source code? (I guess this is exactly
> the same as the previous case, right?)
Ignoring (possible) undefined behavior, and assuming that the compiler
option does what most compilers do with it, since the language does
not define this method of defining a macro, I still agree I would not
expect a change in behavior.
> In all of the above: should I expect the generated machine
> code to change? (assuming all the compiler switches and
> optimization settings are exactly the same)
Here there's a much better chance of seeing a change, especially if
the class initially had public and private members before you changed
them all to public.
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.
> 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
>
> 2) private is also used for inheritance.
>
> (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).
>
> Thanks for any comments,
>
> Carlos
My vote is: behavior no; binary image maybe.
--
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
My guts say no. Since private/public governs accessibility and not
visibility, you will not introduce any changes into the name lookup so the
resulting calls should be the same. This is for functions though.
I could however imagine the code to not compile in some cases. Consider
this:
class A{};
class B{};
void foo( A*);
void foo( B*);
class C:
public A,
private B
{};
C c;
foo(&c);
'&c' will yield a C* which can be converted to an A* but not to a B*, so the
only foo() overload in question would be the one taking an A*. Making B a
public baseclass would now introduce an ambiguity.
Note: I didn't compile this and I'm honestly not sure if it would make a
difference, i.e. if the ambiguity wouldn't already exist with the private
baseclass. This would be consistent with the way functions are handled,
i.e. that visibility is separate from accessibility.
> In all of the above: should I expect the generated machine
> code to change? (assuming all the compiler switches and
> optimization settings are exactly the same)
Yes, I know for example that MSC mangles the access specifier into the
function name.
Uli
> > 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
At least in the second case, program behaviour may change:
______________________ Example 1 ____________________________
#include <ostream>
#include <iostream>
struct base {};
struct derived : private base {};
int main()
{
try
{
throw derived();
}
catch(base&) { std::cout << "Caught 'base'.\n"; }
catch(derived&) { std::cout << "Caught 'derived'.\n"; };
return 0;
}
______________________ Example 2 ____________________________
#include <ostream>
#include <iostream>
struct base { virtual ~base() {} };
struct derived : private base { base* base_ptr() { return this; } };
int main()
{
std::cout << std::boolalpha
<< (dynamic_cast<derived*>(derived().base_ptr()) != 0) <<
'\n';
return 0;
}
_____________________________________________________________
Falk
My understanding is that the standard only talks about 'access
specifiers' not 'different access specifiers'. So I believe that the
layout of the following is unspecified:
struct A
{
public:
int i;
public:
int j;
};
However, the point that they maybe different still holds, since it is
unspecified, there is no guarantee that the above will have the same
layout as:
struct A
{
public:
int i;
private:
int j;
};
Regards,
Richard
--
Richard Corden
Actually, I think it might change if the behaviour depends on
implementation defined behaviour. Consider
struct Example {
public: char a;
private: int b;
private: char c;
....
};
If you have some code which bahaves differently if the address of b is
less or greater than the address of a, then you are into implementation
dependant behaviour (which is OK). The implementation (and hence the
program) MIGHT behave differently if private turns into public.
Unlike Java, in C++ private members are considered in name lookup, so
changing private to public doesn't affect lookup. It does, of course,
affect accessiblity, but that means that some things that used to be ill
formed because name lookup found something that wasn't accessible would
become well formed. Since the program was well formed to begin with,
that doesn't apply. The behavior of the program will be the same. (And
any compiler that gets this wrong is so fundamentally broken that it's
not on the market)
--
-- Pete
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
> For following example,
>
> struct B
> {
> int t;
> };
>
> struct D1 : private B // private inheritance (hold-a)
> {
> D1(){ t = 0; }
> };
>
> struct D2 : public D1
> {
> D2(){ t = 0; } // error, B::t is not accessible.
> };
>
> So, again private and public make difference here.
If I understand correctly, this example is not valid with respect
to my question -- sure, private and public make a difference, but
is not that what counts; I'm starting with a code *that compiles*;
so, if I haev a privately inherited base class, then my code would
only do what it is allowed to do. *Then* I replace the privately
inherited to a publicly inherited. There shouldn't be any error
now: I'm eliminating restrictions, so whatever I was able to do
before, I'm able to do now, and more (except that, again, my
question describes a situation where I will not do anything more,
since I will *only* change the private keyword to public)
> Actually I do not known any compilers really treat
> private and public member differently, because
> access specifiers are purely logical constructs.
My thinking exactly. Private does not determine behaviour; it
simply places semantic restrictions on what the program is
allowed to do, not on the behaviour resulting from what the
program does do.
Carlos
--
True.
> However, the point that they maybe different still holds, since it is
> unspecified, there is no guarantee that the above will have the same
> layout as:
>
> struct A
> {
> public:
> int i;
> private:
> int j;
> };
>
>
True.
"Separated by different access specifiers" is just a
specialized version of "separated by access specifiers".
Since this issue is totally unspecified by standard,
we can not make sure that replacing private with public
will give us the *exactly same* result/layout.
Well, my point is the private inheritance constructs a
"hold-a" relationship while public inheritance yields a
"is-a" relationship. If you replace private with public,
you create a inheritance chain, which is not available
in the original configuration.
Please check the nice examples purposed by Kanze
and Falk.
> > Actually I do not known any compilers really treat
> > private and public member differently, because
> > access specifiers are purely logical constructs.
>
> My thinking exactly. Private does not determine behaviour; it
> simply places semantic restrictions on what the program is
> allowed to do, not on the behaviour resulting from what the
> program does do.
>
Not true for case 2. My above comment was based on case 1.
And even for case 1, it is pretty valid that the compilers can
allocate private members in higher address, and put all public
members in other region, because here the allocation order
is unspecified behavior according to the standard.
There is always the possibility that changing "private" to "public"
with a macro could turn a well-formed program into an ill-formed one:
class A
{
class B;
private:
class B {};
};
will compile with private as "private", but will not compile with
private as "public".
Greg
> "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>.)
Nit pick: I believe your reasoning is incorrect -- well, at
least one can object. It comes down to what we call "defined
in that header" -- If <vector> includs <memory>, then allocator
is defined in the header <vector> -- The header <vector> has
several ways of #defining a symbol; one of them is to use a
#define directive; another one is to #include a header where
the symbol is defined (notice the recursive nature of my
"definition".
Anyway, perhaps a better phrasing would have been: "names that
the header declares or defines" -- this is, IMO, unambiguous,
since it doesn't say anything that suggest a given mechanism
to declare or define.
Anyway, coming back to the original point: since my question
is rather practical in nature, and not "language lawyering",
I'm now curious as to whether I should expect any concrete
manifestation (read: nasty effect) of that undefined behaviour
that occurs when I #define private having included standard
headers...
>>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 could also cause a change in behavior. [...]
> A anA ;
> if ( &anA.a > &anA.b ) //...
>
> In this case, of course, the code has unspecified behavior to
> begin with [...]
> I don't think that this was what Carlos had in mind
Indeed. I mentioned that I start off with a strictly legal
C++ program -- I'm not sure if that implies, strictly speaking,
unspecified or implementation-dependent behaviour, but in my
mind, I was assuming that the program that I start with is
clean enough that it doesn't have any sort of nasties like
the above.
Still, you make a very good and very interesting point, if
only for the fun of thinking about it, and not for the
practical implication it may have with respect to my
original question.
>>My vote is: behavior no; binary image maybe.
>
> The actual examples outvote you, two to one:-).
:-)
It still looks like for the use that I have in mind, which
implies the assumption that I'm starting with a program that
is clean enough and that it does not have bahaviour that is
unspecified, implementation dependent, or undefined, my
initial guess seems correct (assuming that the undefined
effect resulting from #defining a keyword having #included
standard headers does not materialize in practice, with
actual compilers and actual standard library implementations).
Thanks,
Carlos
--
> Actually I do not known any compilers really treat
> private and public member differently, because
> access specifiers are purely logical constructs.
>
> But I do not have a good reason to do such a
> replacement. :-)
No one has explicitly asked me to say why I was asking
such a strange question.
But having seen a few interesting replies, it could be
a good thing to mention that detail.
What I have in mind is debugging/testing (QA kind of
testing). Having client code (the "test protocol")
access to private data members gives you more flexibilty
in terms of easily creating test case scenarios. Of
course, if we're talking production code, I wouldn't
want to even open the source file with a text editor
after the test protocols passed!
In particular, changing all the private to public
is about the worst possible idea!! First of all,
one could *accidentally* change something else that
goes unnoticed. One could then, after all the test
protocols passed and we want to restore the original
file, *forget/overlook* to change back one or several
of the publics, leading to future bugs or trouble.
Also, though less severe consequences, we could
accidentally change a public back to private when
that one was originally a public, leading to
unnecessary annoyment.
That's why I thought #defining private as public for
the purpose of compiling the prorgam that runs the
test protocols would be the least intrusive and
safest way to do that trick. #Defining it from the
command-line with a compiler switch is the safest
way.
One concern, however, is due to the fact that the
generated binaries could change -- that forces us
to remember to recompile the non-testing version
right after we're finished; otherwise, if we leave
the object file and there are no more changes to
the corresponding source file, the next time that
we link it (because other modules changed), we might
run into trouble, since some of the object files are
compiled with one class declaration, and the object
file that we tested in the past with a different
declaration, leading to inconsistent binaries (that
is, there is the possibility).
Carlos
--
You may encounter problems at least with Visual C++ (other compilers
may behave this way): it uses different name linkage for private
functions. In particular, the following program will not link:
----------------------------------------------- A.h
class A {
private:
void f();
};
----------------------------------------------- A.cpp
#include "A.h"
void A::f() { } // linker symbol "private: void A::f()"
----------------------------------------------- main.cpp
#define private public
#include "A.h"
int main()
{
A a;
a.f(); // linker: unresolved "public: void A::f()"
}
-----------------------------------------------
> In particular, changing all the private to public
> is about the worst possible idea!!
I agree, you are to use public interfaces in your tests.
The recommendation is a more granular design: every unit is rather
small and has testable public interface, even if some units are
private for casual user. E.g. we can use forward declarations to make
some classes privately declared. Or we can use "pimpl" idiom to hide
private dependencies with their declarations.
--
Andrei Polushin
>>[...]
>>
>>What I have in mind is debugging/testing (QA kind of
>>testing). Having client code (the "test protocol")
>>access to private data members gives you more flexibilty
>>in terms of easily creating test case scenarios.
>
>
> You may encounter problems at least with Visual C++ (other compilers
> may behave this way): it uses different name linkage for private
> functions. In particular, the following program will not link:
> [...]
That's not really a terrible problem -- I can recompile all the
modules I need to recompile; if we're talking about a very large
project, then that would be a problem; but the debugging test
case scenario should be relatively simple, and should not involve
recompiling half the known universe.
>>In particular, changing all the private to public
>>is about the worst possible idea!!
>
> I agree, you are to use public interfaces in your tests.
Oh wait -- I think you misunderstood; what I meant is that
opening the file with a text editor and *modifying* the file
(replacing private with public) is the worst possible idea.
> The recommendation is a more granular design: every unit is rather
> small and has testable public interface [...]
This is also important (and the test protocol *must* exhaustively
test the functionality of the public interface), but does not
necessarily preclude the usefulness of the test protocol *also*
having access to the private interface.
In particular, imagine a case where you want to validate certain
consistency constraints in the data (say, you have two integer
data members, d_start and d_end, and it must always hold true
that d_end >= d_start). You could have a function that validates
such consistency constraints; how do you verify that function?
It would be great to have access to the private data members to
be able to manufacture inconsistent data and veify if the
function detects the inconsistency -- it could be otherwise
hard; I mean, sure, you could extract and isolate that
function and test it, but then that fails to test it when
interacting with the rest (my example of two ints is quite
silly, but the principle is valid in the general case, when
the consistency constraints to be evaluated is more complex).
Also, what happens if you need to check something that happens
at a very high level? What I mean is that the design may be
granular, but you need to verify something that involves
20 levels of "sub-objects" and delegation, involving perhaps
a long sequence of past events that have led to the present
state. It could be easier to simply "manufacture" (by having
access to private data members) what we know would be the
accumulated effect of those past events, and then test it,
instead of having to reproduce the long list of past events;
maybe you don't even know what that list of past events is,
and maybe you're trying to verify what your code does when,
as the result of who knows what past events, you reach a
certain present state.
I'm not saying that #defining private as public is the way
to run test protocols; I simply think that it is an
interesting alternative, that can be quite useful in certain
situations -- I wanted to know if I should expect the trick
to work in the general case.
Cheers,
Carlos
--
[...]
> >>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 could also cause a change in behavior. [...]
> > A anA ;
> > if ( &anA.a > &anA.b ) //...
> > In this case, of course, the code has unspecified behavior to
> > begin with [...]
> > I don't think that this was what Carlos had in mind
> Indeed. I mentioned that I start off with a strictly legal
> C++ program -- I'm not sure if that implies, strictly speaking,
> unspecified or implementation-dependent behaviour, but in my
> mind, I was assuming that the program that I start with is
> clean enough that it doesn't have any sort of nasties like
> the above.
The above is strictly legal. The standard just doesn't make any
guarantees with regards to whether the condition in the if is
true or not. So it is a strictly legal program with two
different possible outputs. (And it's unspecified which will
occur.)
Strictly legal, of course, doesn't mean that it has any
practical utility:-). I can't imagine anything along these
lines in real code.
> Still, you make a very good and very interesting point, if
> only for the fun of thinking about it, and not for the
> practical implication it may have with respect to my
> original question.
> >>My vote is: behavior no; binary image maybe.
> > The actual examples outvote you, two to one:-).
> :-)
> It still looks like for the use that I have in mind, which
> implies the assumption that I'm starting with a program that
> is clean enough and that it does not have bahaviour that is
> unspecified, implementation dependent, or undefined, my
> initial guess seems correct (assuming that the undefined
> effect resulting from #defining a keyword having #included
> standard headers does not materialize in practice, with
> actual compilers and actual standard library implementations).
I'm not sure I agree. In particular, I can imagine that the
example with the exception crops up occasionally in real code
(and I wouldn't say that the example with dynamic cast is
unreasonable either, although I can't think of a good case where
it would be used off hand).
--
James Kanze (Gabi Software) email: 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
>>>In this case, of course, the code has unspecified behavior to
>>>begin with [...]
>
>>>I don't think that this was what Carlos had in mind
>
>>Indeed. I mentioned that I start off with a strictly legal
>>C++ program [...]
>
> The above is strictly legal. [...]
>
> Strictly legal, of course, doesn't mean that it has any
> practical utility:-). I can't imagine anything along these
> lines in real code.
That's exactly what I meant -- since the application I had in
mind for the private/public trick involves production code, we
work with the assumption that the code is *clean* enough to be
free of undefined, unspecified, or implementation-dependent
code (well, maybe a few "clean" platform-dependent things
here and there -- for a suitable definition of "clean" :-)).
That the assumption holds or not, that's another thing, but
we have to work under that assumption -- in fact, if changing
private to public changed the behaviour of the program, then
I would call it a *big success* as far as test protocols go!!
We detected an unspecified-behaviour condition that most
likely should not be there (if we're talking production code).
Kind of the same idea as memory/environment disruptors.
>>It still looks like for the use that I have in mind, which
>>implies the assumption that I'm starting with a program that
>>is clean enough and that it does not have bahaviour that is
>>unspecified, implementation dependent, or undefined, my
>>initial guess seems correct (assuming that the undefined
>>effect resulting from #defining a keyword having #included
>>standard headers does not materialize in practice, with
>>actual compilers and actual standard library implementations).
>
>
> I'm not sure I agree. In particular, I can imagine that the
> example with the exception crops up occasionally in real code
> (and I wouldn't say that the example with dynamic cast is
> unreasonable either, although I can't think of a good case where
> it would be used off hand).
As I said, I was mostly interested in the case of private
being used for member access specification, given that
private inheritance is supposed to be rare (it is rare in
my code anyway -- I would venture to say that it does not
show up *ever* in my "high level" real code, which is the
one I would be debugging with this trick; the lower-level
"foundational" code is supposed to be completely general-
purpose and stand-alone that it can be tested easily with
regular methods).
Plus, the only case where it seems to matter is when catch
clauses for both the base and the privately inherited class
are used *in that particular order* -- seems kind of specific
to be quite rare in real code. For overloading resolution
(including templates combined with overloaded functions), I
can't come up with an example in which things would change --
if you have overloaded functions receiving B and D, then
regardless of the relationship D is-a B holding or not, if
you pass a B or a D, you have exact match; if you have a
function receiving B and a template for the rest, then when
you call it with a D, regardless of the is-a relationship,
the template version will always be chosen, since an implicit
conversion is needed, whereas the instantiated template
provides an exact match. Am I missing something?
Carlos
--
From a practical point of view I think so.
From a formal point of view you're prohibited from defining a macro
with the same name as a keyword if any standard library headers are
included.
An alternative is to directly support testing in the classes (it can be
as simple as a "friend" declaration).
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
> > I'm not saying that #defining private as public is the way
> > to run test protocols; I simply think that it is an
> > interesting alternative, that can be quite useful in certain
> > situations -- I wanted to know if I should expect the trick
> > to work in the general case.
> From a practical point of view I think so.
Provided he's not using private inheritance. (Even then, I'd be
surprised if he had a problem unless private inheritance was
used in the exception hierarchy. And only in exceptional cases
then.)
> From a formal point of view you're prohibited from defining a
> macro with the same name as a keyword if any standard library
> headers are included.
> An alternative is to directly support testing in the classes
> (it can be as simple as a "friend" declaration).
This is what I've done (or rather seen done) in the past. Every
class X has a declaration: friend class TestX. Anytime you want
to access a private member in the test, you just add a function
to TestX (which, of course, as a class only exists for this
reason, so we don't care that it isn't well designed:-)).
--
James Kanze (Gabi Software) email: 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
Truth be told I didn't think of that case, thanks! :-) It's subtle.
Illustration code, checking for conversion to inaccessible base at run-time:
#include <iostream>
#include <ostream>
#if 0
# define private public
#endif
void out( char const s[] ) { std::cout << s << std::endl; }
class IsSerializable {};
class Base {};
class Derived: public Base, private IsSerializable {};
template< class A, class B >
class IsConvertibleFromTo
{
static char (&convert( ... ))[1];
static char (&convert( B const* ))[2];
static A const* a();
public:
// Fails to compile if B is an inaccessible base class of A.
enum{ yes = (sizeof( convert(a()) ) == 2) };
};
template< class A, class B >
bool isConvertibleFromTo()
{
try { throw static_cast<A const*>( 0 ); }
catch( B const* ) { return true; }
catch( ... ) { return false; }
}
int main()
{
out( IsConvertibleFromTo<Derived, Base>::yes? "B" : "No B" );
out( isConvertibleFromTo<Derived, IsSerializable>()? "S" : "No
S" );
}
Change the "#if 0" to "#if 1" and the output of the program is changed.
Now the question for us language definition nit-pickers (I currently
doubt that my question has practical value),
* How can we can we check for conversion to an inaccessible base class
at compile time rather than run time?
Additional question: can this have practical value?
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
Carlos, you could for every class Foo have a friend class
Foo_UnitTest, which requires neither hacks nor changes to
any code.
Uli
This was discussed in comp.std.c++ under a topic titled "Q: private
inheritance and ambigious names".
In addition to changed "catch" behavior, you can get different runtime
dynamic_cast behavior (dynamic cast that would fail with private will
now succeed).
Also, the following may be legal (I'm not entirely sure).
#define foo x##private
If it is legal, changing private to public might change either run-time
or compile-time behavior.
Well, since we can not add friend class Foo_UnitTest without
touch the class Foo, the above method is quite expensive, isn't it?
Also it is possible that someone will use the class Foo_UnitTest
for other purposes.
BTW I really do not see why the replacement is necessary.
1. For debugging:
Since the debugger is part of the implementation, the access
control should not be an issue. All the unspecified behaviors
will become perfectly well-defined behaviors, provided we
stay with the same compiler/debugger.
2. For unit testing:
Also I do not see the benefits for unit testing while all the objects
will be teared up. All we need to test are the public interfaces
and internal state probing will introduce unnecessary
dependencies between the test-cases and classes.
Logger/analyzer utilities can be used if the internal states are
really necessary.
Or, I missed something important for testing?
>>What I have in mind is debugging/testing (QA kind of
>>testing). Having client code (the "test protocol")
>>access to private data members gives you more flexibilty
>>in terms of easily creating test case scenarios.
>
> [dangers of various ways of changing private to public]
>
> Carlos, you could for every class Foo have a friend class
> Foo_UnitTest, which requires neither hacks nor changes to
> any code.
Well, after hearing the suggestion from you and from Alf,
yes, it feels like "DUH!" :-)
At least the question did trigger an interesting discussion
(with little practical value, at least with respect to my
original intent, but still interesting)
Cheers,
Carlos
--
(I started a thread on this topic recently on Boost-users.) The
situation I have is a class, with a public interface; but the
heavy lifting is done by private methods, that implement some
extremely non-trivial mathematics.
1) If the public interface is something that's hard to fake up for
unit testing (i.e. involves BigHonkinHairyClasses, to coin a
phrase from Scott Meyers), the cost of hooking up and maintaining
a unit test that talks to the public interface may be
prohibitive. (Alas, our code base has this problem in spades.)
2) Unit tests of the public interface don't do a good job of
pinpointing math errors; an incorrect answer out of the public
interface could result from a mistake anywhere in the math code.
Therefore, it's much preferable to unit test the private methods
directly.
3) It's much, much easier to test corner cases of mathematical
algorithms directly, as opposed to trying to come up with a
BigHonkinHairyClass object with just the right internal state to
poke at a math algorithm in a particular way.
(2 and 3 really amount to a desire to do "white box"-ish unit
tests.)
Responses on the Boost Users list included to:
A) Do the "friend class Tester" thing, as Ulrich Eckhardt said
above. Involves adding a friend declaration to classes, which may
not be possible. Also has problems under some circumstances
(pimpl idioms...)
B) Do the "#define private public" thing as discussed in this
thread. Evil, but carefully contained, fed, and taken-for-a-walk-
twice-daily evil. :-)
C) Do the "Inherit from the class and change the visibility,
and/or add interface to make the class' guts available for
testing" thing, proposed by Jason Aubrey. Requires using
"protected" instead of "private", which has other implications,
and may not be possible.
D) Break the complex mathematical innards out into a separate
class, that exposes them for use. (I think David Abrahams
advocated this approach.)
Personally, I think A frequently works, and isn't too ugly to live
with.
D is a nice ideal, and I'll go there if I can. Given the code base
I'm already working with, that kind of redesign will seldom be
practical (alas).
Alas, B is evil, but it's the only idea I've gome up with, or heard
from anybody else, that allows unit tests access to class' innards,
with _no_ change to class design or implementation.
----------------------------------------------------------------------
Dave Steffen, Ph.D.
Software Engineer IV Disobey this command!
Numerica Corporation - Douglas Hofstadter
dgsteffen at numerica dot us
Jiang wrote:
> 2. For unit testing:
>
> Also I do not see the benefits for unit testing while all the objects
> will be teared up. All we need to test are the public interfaces
> and internal state probing will introduce unnecessary
> dependencies between the test-cases and classes.
> Logger/analyzer utilities can be used if the internal states are
> really necessary.
>
> Or, I missed something important for testing?
See my reply to Andrei Polushin earlier in this thread for an
argument -- I'm not saying or suggesting that you're mistaken;
simply that in that post, I gave some arguments in favor of
testing more than just the public interfaces.
Carlos
--
For legacy code, it could be useful to inject several calls to logger
object at some control points of that code, then examine the results
gathered by logger in your test.
Such technique requires no changes in design, no hacking, and isolates
tester from implementation details.
--
Andrei Polushin