Constructor / Destructor
In order to maintain the run time type information it is necassary to set it in the VObject member variable, when any VObject derived class is constructed.
VObject derived classes specify their run-time types, in their constructor, as a default argument. Every derived object always calls its immediate base class by it's constructor, when being constructed. By this means it is always possible for any "non final" class to be inherited and maintain it's correct, unique, run time type.
Where it is important that a class is not inherited further, we merely specify the run-time type in the call to the immediate base constructor directly. No argument for the run-time type is provided in the constructor for the subclass, and it can be considered "final".
Although an explicit call to the immediate base class is not required for the purposes of the compiler or the language, it is essential to maintain our concept of run-time type, and this has consequences.
Whilst there is no reason to prevent a copy constructor being used, care must be taken to provide an explicit copy constructor if one wishes to use that language construct. In practice the majority of the information contained in our objects is pointers to other objects on the heap, and this represents a further coding overhead for the copy constructor.
Error handling is detailed in it's own section, but suffice to say that each and every VObject derived class may potentially have it's own error handler. The error handler is a _cdecl function pointer, and it is always passed in the constructor for any VObject derived class. This scheme has it's benefits, but it too has consequences. Again, it would not preclude the implementation of a copy constructor, but it does increase it's coding overhead.
Where a copy constructor is required, Serialize() is always available. It is accepted that this is a fairly brutal method for a simple little thing like the copy constructor. For this reason, sometimes, library objects overload operator=, and this is our preferred approach to making equivalent objects. We rarely use the copy constructor, on the basis that operator= overloads are more "visible", easily managed and come with a minimal coding overhead.
It has probably also become clear that our concept of run-time type is not really compatible with multiple inheritance. We would tend to avoid multiple inheritance anyway for the sake of sanity. We have never found the avoidance of multiple inheritance to be a hinderance. Avoiding a "good" run-time type scheme for the sake of any of these these moderately incompatible features of the language would undoubtedly be a hinderance.
The c++ destructor is is not virtual by default, and so we declare it virtual in VObject, the absolute base class. |