From: nikki@trmphrst.demon.co.uk (Nikki Locke)
Newsgroups: comp.lang.c++
Subject: Re: Calling pure virtual functions in base class constructor
Date: 11 Nov 92 11:12:37 GMT
Reply-To: nikki@trmphrst.demon.co.uk
Organization: Trumphurst Ltd.
X-Mailer: cppnews $Revision: 1.20 $

In article <1992Nov10.010626.26528@ucc.su.OZ.AU> maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
> In article <720990361snx@trmphrst.demon.co.uk> nikki@trmphrst.demon.co.uk writes:
> > ... it is quite legal to have a definition of a pure 
> >virtual function, thus ...
> >
> >class A
> >  {
> >    // ...
> >      ~A() { purefunc(); }
> >      virtual void purefunc() = 0;
> >  };
> >
> >void A::purefunc()
> >{
> >  cout << "You called a pure virtual function !\n";
> >}
> >
> >This facility might be useful when you want your abstract base class to 
> >provide some kind of default behaviour, but you want to force derived 
> >classes to add additional behaviour (or, at least, hint strongly :-).
It seems I did not explain this too well. Ask yourself what use is a 
definition of a pure virtual function ? It can only be called statically, 
so why not make a non-virtual function (with a different name) to do the 
job ? The only reason _I_ can think of is to hint to the person deriving 
from the class that some of the common/default things they want to do in 
their derived function are already written for them. It is quite common in
a virtual function in a derived class to call the base class version as
well as adding derived class specific behaviour. This is why I used 
the term "default behaviour".

Alternative explanations for the _usefulness_ of definitions of pure 
virtuals welcome.

> 
> 	Not quite. It does not supply 'default behaviour', but 
> is called in two by a statically, i.e. like
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sorry, don't understand a word of this !
> 	A::purefunc(); // from inside a member
Yes, this is how you force a call to a pure virtual. 
> 	a.purefunc(); // from outside the object
Surely this will NEVER call the pure virtual, because you cannot have an
object of type A (A is an abstract class).

We were discussing a call in a base class destructor. I thought this would
always call the pure virtual (because any derived class object has
already been destructed at that point). However, I have re-read the ARM 
(s10.3 p215), and it gives an example ...

arm> class A {
arm> 	virtual void f() = 0;
arm> 	A() {
arm> 		A::f();	// ok
I ask, why is the A:: necessary here ? If f was NOT pure, A::f would 
definitely be called, because there is no other f is available during the 
constructor. Is it just to make the compiler writer's life one tiny bit 
easier (i.e. always despatch via the vtable unless A:: is present) ?
arm> 	}
arm> };
arm> 
arm> void A::f()		// defined somewhere
arm> {
arm> 	// ...
arm> }

The arm also states (s12.7 p295)
arm> The effect of calling a pure virtual function directly or indirectly
arm> for the object being constructed from a constructor, except using
arm> explicit qualification, is undefined.
So the insistence on the A:: qualification is definitely deliberate. Can 
anyone explain why ? (Bjarne ?)

> >
> >Actually, it occurrs to me that it should be possible to do this yourself,
> >without adding to code size (probably) - just declare your virtual 
> >functions ...
> >
> >class A
> >  {
> >    // ...
> >      ~A() { purefunc(); }
> >      virtual void purefunc() = 0;
> >  };
> >
> >inline void A::purefunc() { assert(0); }
> 
> 	No, this cannot work. The body of a pure virtual cannot be
> called though a pointer or reference, only from a 'value'. Had
> the pure specifier not been included, the body would have been
> called virtually during construction of the A base only.
 You CAN (IMHO) call a pure virtual using a pointer or reference, using
pointer->A::purefunc();

> >Pure virtual functions can only be called explicitly, under circumstances 
> >where the actual type can be deduced at compile time, which are the 
> >conditions allowing inline virtuals to be expanded inline. Then again, I 
> >could be wrong.
> 
> 	IMHO you are wrong. It is not a matter of deduction, the programmer
> must explicitly override the virtual call mechanism.  Virtual calls
> (indirections via the vtble) can be replaced by direct calls only
> in code outside the object where the compiler can deduce the actual
> object type, this cannot ever be the case inside a member function
> as far as I can see (because no member can know what the most derived
> object is).
After my re-reading of the ARM, I realise that I am, indeed, wrong. 
Despite the fact that the compiler can easily convert calls to any
virtual function (pure or otherwise) to a direct call in a constructor or 
destructor, the ARM states that it should NOT do so in the case of pure 
virtuals.

Sorry about the length of this posting, but I really would like to 
understand the reasons for all this :-)
-- 
Nikki Locke,Trumphurst Ltd.(PC and Unix consultancy) nikki@trmphrst.demon.co.uk
trmphrst.demon.co.uk is NOT affiliated with ANY other sites at demon.co.uk.
Newsgroups: comp.lang.c++