Xref: utzoo comp.std.c++:495 comp.lang.c++:10830 Path: utzoo!mnetor!tmsoft!torsqnt!news-server.csri.toronto.edu!cs.utexas.edu!uunet!microsoft!jimad From: jimad@microsoft.UUCP (Jim ADCOCK) Newsgroups: comp.std.c++,comp.lang.c++ Subject: Re: Accesibility change in virtual functions Message-ID: <59918@microsoft.UUCP> Date: 18 Dec 90 19:29:31 GMT References: <1990Dec7.205909.14021@relay.wpd.sgi.com> Reply-To: jimad@microsoft.UUCP (Jim ADCOCK) Organization: Microsoft Corp., Redmond WA Lines: 100 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(); }