Re: inheritance, list of objects, polymorphism
 
* Vladimir Jovic:
Alf P. Steinbach wrote:
* Vladimir Jovic:
James Kanze wrote:
 > General rule: assignment and external copy don't work well with
inheritance.  (In my own code, I've gradually been introducing a
PolymorphicObject base class, with a virtual destructor and a private
copy constructor and assignment operator.  With the rule that classes
designed to be used polymorphically should inherit from
PolymorphicObject.)
I do not understand why you said that "assignment and external copy 
don't work well with inheritance."
Mainly it has to do with C++ variables directly being of the size of 
the statically known type and directly containing an object of that 
type, instead of just being pointers[1] as in Java and C# and like 
languages.
When sizeof(Derived) > sizeof(Base) this means that
  Base o = Derived();
performs a /slice/ of the Derived object; 'o' contains only the Base 
stuff of that original object.
Ok, this explains it :)
[snip]
For a PolymorphicObject base class like James mentioned you therefore 
generally want to introduce two restrictions, and support one main 
functionality:
  * Inhibit client code "slice" copying.
    This is done by making the assignment operator private and the
    copy constructor protected. James wrote "private" copy constructor
    but that's a bit impractical. For you want to allow derived classes
    to be clonable, and cloning is best expressed in terms of internal
    copy construction.
The assignment operator is private and not implemented, or just private?
There's usually no need to implement it.
I can't imagine why one need it, but it's always like, someone's going to need 
that anyway.
So the answer is "it depends", but in general, no implementation.
  * Make sure that objects can only be created dynamically.
    The reasonable way is to make the destructor protected.
But if you make the constructor protected, and leave the destructor 
public, then you do not need next point. Or, am I missing something?
Yeah. First of all you need the destructor protected anyway, to stop the 
long-fingered client code programmer from doing 'delete &*smart_ptr'. Or more 
indirectly. And secondly, with M classes with on average N constructors each 
then for protected constructors you need M*N factory functions, while with 
destructor protected you need, uh, none. Or just a single common one, if 
wrapping of new expression is regarded as a factory function. :-)
  * Force use of smart pointer.
    James relies on garbage collection so he probably doesn't do this,
    but there are two aspects: ensuring that any newly created object's
    raw pointer is immediately stored in a smart pointer, and ensuring
    that only the smart pointer class has access to destroy an object.
    One way to do the first it is to overload the class' allocation 
function
    (operator new) so that any direct 'new' expression would be overly
    complicated. For C++98 then provide a macro that supplies the
    requisite magic incomprehensible expression and ensures the pointer
    is immediately wrapped in a smart pointer, before client code can
    get at it. For C++0x I think the improved support for argument
    forwarding makes the macro unnecessary. Anyways, one way to do the
    second is to make destructor protected (which you'd do anyway for
    the bullet point above), and grant friendship to the smart pointer.
Cheers & hth.,
- Alf