[comp.std.c++] Accesibility change in virtual functions

pal@xanadu.wpd.sgi.com (Anil Pal) (12/08/90)

I am posting this for Martin Hitz, who does not have posting access to the net.
Please send e-mail replies to Martin at hitz@csi.UOttawa.CA.

Note: I checked that this is the neahiour of cfront 2.o also, and
indeed is explicitly stated in the ARM (p.255, section 11.6).  Martin
would like to raise the issue for discussion, hence I am posting to
comp.lang.c++ and comp.std.c++.

-- 
Anil A. Pal,	Silicon Graphics, Inc.
pal@sgi.com	(415)-335-7279

<===== Begin forwarded message =====>
From hitz@csi.UOttawa.CA  Tue Dec  4 09:47:20 1990
Date: Tue, 4 Dec 90 12:43:56 EST
From: hitz@csi.UOttawa.CA (Martin Hitz)
Message-Id: <9012041743.AA22998@csi.UOttawa.CA>
To: pal@csi.UOttawa.CA
Subject: comp.lang.c++
Status: RO

I find it awkward that it is possible (at least with g++ and Zortech 2.0)
to implicitely call a private member function via the virtual mechanism as
in the following example:

	class B {
	 public:
		virtual void f() { cout << "B\n"; }
	};

	class D: B {
		void f() { cout << "D\n"; }
	};

	main()
	{
		D  d;
		B& b = d;	
		b.f();		// prints "D"
	}

My opinion is that this shouldn't be possible, i.e. the compiler
should complain about the private version of f() in the derived 
class D.

Any comments?

Best regards, Martin Hitz

hitz@csi.UOttawa.CA

jimad@microsoft.UUCP (Jim ADCOCK) (12/19/90)

In article <1990Dec7.205909.14021@relay.wpd.sgi.com> hitz@csi.UOttawa.CA writes:
|I am posting this for Martin Hitz, who does not have posting access to the net.
|Please send e-mail replies to Martin at hitz@csi.UOttawa.CA.
|
|Note: I checked that this is the neahiour of cfront 2.o also, and
|indeed is explicitly stated in the ARM (p.255, section 11.6).  Martin
|would like to raise the issue for discussion, hence I am posting to
|comp.lang.c++ and comp.std.c++.
|I find it awkward that it is possible (at least with g++ and Zortech 2.0)
|to implicitely call a private member function via the virtual mechanism as
|in the following example:
|
|	class B {
|	 public:
|		virtual void f() { cout << "B\n"; }
|	};
|
|	class D: B {
|		void f() { cout << "D\n"; }
|	};
|
|	main()
|	{
|		D  d;
|		B& b = d;	
|		b.f();		// prints "D"
|	}
|
|My opinion is that this shouldn't be possible, i.e. the compiler
|should complain about the private version of f() in the derived 
|class D.
|
|Any comments?

First, I think D needs to derive from a public B otherwise your compiler
ought to prohibit the implied coercion of a D ref to a B ref.  If you don't
mean for B to be a public base, then this discussion is not an issue --
your compiler ought to prohibit it.  Is this a point of confusion?

Next, for comparison, I've added a function g() below for which I've tried to 
adjust access control.  (Your C++ compiler should prohibit this attempt)

For reference, what section 11.6 says is : "The access rules (sec11) for a 
virtual function are determined by its declaration and are not affected by the 
rules for a function that later overrides it."

So compilers indeed ought to accept this program [given D inherits publicly]
as you suggest.  The question then, is should this rule be changed, and if so, 
how?

Note that some people might actually consider this definition a "feature."
B might require some low level methods that it doesn't generally make
sense to expose in D, but which are methods that a class D needs to implement
in order for B to work correctly.  An example pops to mind:  Let f() return
a class's metaclass representation.  At the primitive level we desire to 
allow people access to runtime type information, but at a higher programming
level we want to prohibit such access -- lest programmers fall into the
bad habit of programming based on exact type.  At the primitive level 
however, low level functionality such as file I/O needs access to exact
type information, so it makes sense to allow access at the base class
level.  But D needs to override f() in order to return D's correct metaclass
information.  Voila -- the access to virtual functions rules aren't a bug,
their a feature! 1/2 :-)

Pragmatically, one might note that class B may be compiled long before
D, and therefor the only way to prohibit access to virtual D::f() is
to prohibit conversion of a D ref to A B ref.  One might ask then if the
assignment of a D ref to B ref shouldn't require an explicit conversion?

Still, I think when D inherits from a public B, it is stating that a D
can be used as a B.  This is only possible if all B's public members remain 
accessible.  If you don't want a D to be usable as a B, inherit B privately,
and use access control to promote those methods of B to public access
that you wish D to support.  Compilers then will correctly prohibit 
conversion of a D to a B.

I recommend no change.

// comparison of attempt to change access control verses overloaded virtual
// function follows [shouldn't compile]:

	class B {
	 public:
		virtual void f() { }
		virtual void g() { }
	};

	class D: public B {
	 private:
		void f() { }
		B::g;
	};

	main()
	{
		D  d;
		B& b = d;	
		b.f();
		b.g();
	}