Re: Rationale for base class pure virtual function call from ctor/dtor
being undefined behaviour.
On 16/01/2012 18:02, Paul <pchrist wrote:
"Leigh Johnston"<leigh@i42.co.uk> wrote in message
news:tfydnWenHpz4z4nSnZ2dnUVZ8hidnZ2d@giganews.com...
On 16/01/2012 16:14, Paul<pchrist wrote:
"Leigh Johnston"<leigh@i42.co.uk> wrote in message
news:dZmdnf_yLtEuronSnZ2dnUVZ8nydnZ2d@giganews.com...
On 16/01/2012 14:14, Paul<pchrist wrote:
"Leigh Johnston"<leigh@i42.co.uk> wrote in message
news:KuednRghMrM8gInSnZ2dnUVZ8uadnZ2d@giganews.com...
On 16/01/2012 12:04, Paul<pchrist wrote:
[snip]
http://www.artima.com/cppsource/nevercall.html
That is just one opinion; another opinion is that calling virtual
functions from ctors and dtors is OK as long as you are aware that the
object is an instance of the base type when still in base ctor or
dtor.
Remember the abstract class cannot exist as an object so there is no
object
on which to invoke a member function. A non-static member function
needs
to
be invoked on an object.
Of course there is an object; a partially constructed object to be
precise. When in a base class ctor the object is currently an instance
of
the base class type and whether or not the class is abstract has no
bearing on this fact.
You are viewing the partially constructed object as an instance of the
abstract base object.
That is what the effective type of the partially constructed object is
whilst it is in the base class ctor; a class invariant can be said to
start in the body of a ctor and this is true for base classes as well as
derived classes irrespective of the presence of virtual functions (pure or
not).
But this goes against the concept of not being able to instanciate an
abstract class type.
No it doesn't.
A pure virtual function is intended as an interface that will (must) be
implemented in a non abstract derived class.
If you want to call Base::foo during construction you could do the
following:
<code ref="how it is">
class Base{
public:
Base(){std::cout<<"Base constructor...\n"; }
virtual void foo()=0;
};
void Base::foo(){std::cout<<"Base foo...\n";}
class Derived : public Base{
public:
Derived(){ std::cout<<"Derived constructor...\n"; Base::foo(); }
void foo(){std::cout<<"Derived foo...\n";}
};
int main(){
Derived d;
Base* bp =&d;
bp->foo();
}
</code>
You can also make a non-virtual call of Base::foo() from Base::Base()
according to the standard.
The PVF must be implemented by the derived class and not by the base class.
Wrong. Pure virtual functions can have definitions.
If para 6 of 10.4 did not exist this would not be the case. This case you
propose is:
<code ref="how you think it should be">
class Base{
public:
Base(){std::cout<<"Base constructor...\n"; foo();}/*UB*/
virtual void foo()=0;
};
void Base::foo(){std::cout<<"Base foo...\n";}
class Derived : public Base{
public:
Derived(){ std::cout<<"Derived constructor...\n";}
void foo(){std::cout<<"Derived foo...\n";}
};
int main(){
Derived d;
Base* bp =&d;
bp->foo();
}
</code>
If this were allowed then we no longer have a situation where the derived
class has full control over the implementation of the PVF. Here we have one
version of foo invoked during object construction of which the derived class
has no control over its implementation.
Basically the PVF is no longer just an Interface if you allow this
behaviour.
A pure virtual function with a definition is not "just an Interface"; a
pure virtual function with a definition is simply a virtual function
that must be overridden. Just because a virtual function must be
overridden does not mean that it makes no sense for its own
implementation to be called within the context of the class's ctor or
dtor; what makes sense depends on the overall object oriented design of
the system of which the virtual function plays a part.
/Leigh