Topic: Q: Public access to private member functions via virtual functions.


Author: jason@cygnus.com (Jason Merrill)
Date: 06 Mar 1995 23:54:07 GMT
Raw View
>>>>> Roland Radtke <Roland.Radtke@arbi.informatik.uni-oldenburg.de> writes:

> I happened across some behaviour which struck me as rather weird:
> the ANSI C++ Standard to come explicitly allows public access to
> private member functions if the member function can be interpreted
> as overriding a virtual member in some class higher up the inheritance
> graph. Why is that so?

Because access control is checked statically in C++.

Jason




Author: Roland.Radtke@arbi.informatik.uni-oldenburg.de (Roland Radtke)
Date: Mon, 6 Mar 1995 14:06:50 GMT
Raw View
Hi !

I happened across some behaviour which struck me as rather weird:
the ANSI C++ Standard to come explicitly allows public access to
private member functions if the member function can be interpreted
as overriding a virtual member in some class higher up the inheritance
graph. Why is that so? I believe it's very practicable in writing
compilers but might prove a possible problem if people start reusing
classes heavily.

My mistaken bug report and the answer to it follow (I don't have much
time with the CeBIT approaching).

So long,

Roland.

----------------------------------------------------------------------------------

Hi there,

Thanks for the bug report.

This is what is required by the draft ANSI/ISO C++ standard -


  10.3  Virtual functions                                [class.virtual]

1 Virtual  functions  support  dynamic   binding   and   object-oriented
  programming.   A class that declares or inherits a virtual function is
  called a  polymorphic  class.

2 If a virtual member function  vf is declared in a class  Base and in a
  class    Derived,  derived directly or indirectly from  Base, a member
  function  vf with the same name and same parameter list as    Base::vf
  is  declared,  then  Derived::vf is also virtual (whether or not it is
  so declared) and it  overrides51)  Base::vf.  For convenience  we  say
  that  any  virtual function overrides itself.  Then in any well-formed
  class, for each virtual function declared in that class or any of  its
  direct  or  indirect  base classes there is a unique  final  overrider
  that overrides  that  function  and  every  other  overrider  of  that
  function.
  __________________________
  51) A function with the same name but a different parameter list  (see
  13)  as  a  virtual  function  is not necessarily virtual and does not
  override.  The use of the  virtual specifier in the declaration of  an
  overriding  function  is  legal  but  redundant (has empty semantics).
[*****]  Access control (11) is not considered in determining
overriding.  [*****]


Regards,
 Rohan
------------------------------------------------------------------------
Excerpts from BugReport.Gnu: 4-Mar-95 no subject (file transmission)
Roland Radtke@arbi.infor (3435)

> Hello!

> I'd like to report something of which I'm not quite sure
> whether it's a bug or not. The behaviour I find strange
> is not only specific to g++ but also occurs using the standard
> Sun Compiler "SC1.0"(whatever that is...).

> I believe I found a way of accessing private member functions of
> an inherited class.


> Here's my gcc and machine specification:

>   tracy:~/tmp/test 114) g++ -v
>    gcc -v
>   Reading specs from /usr/local/lib/gcc-lib/sparc-sun-sunos4.1.3/2.6.3/specs
>   gcc version 2.6.3

>   tracy:~/tmp/test 117) uname -a
>   SunOS tracy 4.1.2 2 sun4c


> Here is a simple sample of a program exploiting the strange behaviour:

> -test.hh---------------------------------------------------------------
> class A {
> public:
>   virtual void test() =0;
> };

> class B : public A {
> private:
>   void test();
> };
> -----------------------------------------------------------------------

> Although I cannot find a place in the ARM explicitly mentioning what
> to do in such situations, I am strongly convicted that the derived
> class B should contain a public member void test(). Yet, no error
> occurs during compilation, and, worse: main() can call B's private
> test() function, as is shown by compiling and executing the following
> program.

> -test.cc---------------------------------------------------------------
> #include "test.hh"
> #include <iostream.h>

> void B::test() {
>   cout << "B::test() called.\n";
> }

> void main() {
>   A* a;
>   a=new B;
>   a->test();
> }
> -----------------------------------------------------------------------

> Here's what happens:

>   tracy:~/tmp/test 134) g++ -o test test.cc

>   tracy:~/tmp/test 135) test
>   B::test() called.


> CC behaves alike:

>   tracy:~/tmp/test 136) CC -o test test.cc

>   tracy:~/tmp/test 137) test
>   B::test() called.


> The conflict with "proper" (in)visibility of inherited functions
> appears more clearly in the following context:
>
> -test2.hh---------------------------------------------------------------
> class A {
> public:
>   virtual void test() =0;
> };

> class B : public A {
> private:
>   void test();
> };

> class C : public B {
> public:
>   void test2();
> };
> -----------------------------------------------------------------------

> -test2.cc---------------------------------------------------------------
> #include "test2.hh"
> #include <iostream.h>

> void B::test() {
>   cout << "B::test() called.\n";
> }

> void C::test2() {
> #ifdef DIRECT
>   test();
> #elif INDIRECT
>   this->test();
> #elif ERROR
>   A::test();
> #else
>   ((A*)this)->test();
> #endif
> }

> void main() {
>   C c;
>   c.test2();
> }
> -----------------------------------------------------------------------

> The results are as follows:

>   tracy:~/tmp/test 142) g++ -DDIRECT -o test test2.cc
>   test2.cc: In method `void C::test2()':
>   test2.cc:4: method `void B::test()' is private
>   test2.cc:10: within this context
>
>   tracy:~/tmp/test 143) g++ -DINDIRECT -o test test2.cc
>   test2.cc: In method `void C::test2()':
>   test2.cc:4: method `void B::test()' is private
>   test2.cc:12: within this context
>
>   tracy:~/tmp/test 144) g++ -DERROR -o test test2.cc
>   /usr/tmp/cca012171.o(.text+0x48): undefined reference to `A::test(void)'
>   collect2: ld returned 1 exit status
>
>   tracy:~/tmp/test 145) g++ -o test test2.cc

>   tracy:~/tmp/test 146) test
>   B::test() called.

> g++ refuses to access test() in any conventional way, but calls B's
> private test() method if treated as an A pointer.

> So: Is this a bug or a feature ? :)

> So long,
> and keep up the good work,

> Roland.