TITLE: virtual functions in constructors (Newsgroups: comp.lang.c++.moderated, 6 Dec 99) CYREN: cyren@my-deja.com (Bengt Cyren) |> > Fellow developers. For a beginner, the fact that virtual functions |> > doesn't work "as expected" in base ctors may come as a surprise. I've |> > been aware of this pitfall for quite some time now. Still, there is a |> > situation where I really would like the base ctor to use the vtable |> > from the descendant. STEINBACH: "Alf P. Steinbach" |> This problem is Frequently Asked Question, and so I believe it's in |> the FAQ (moderator: could you insert an URL here?). However, |> {See the banner at the end of this article. -mod} |> last time the question popped up there was some discussion, so I'll |> just summarize. |> |> 1 Why can't I call functions virtually from a constructor? |> |> Some languages, e.g. Java, allow virtual calls of functions from a |> constructor. KANZE: kanze@gabi-soft.de Some languages, e.g. Java, don't care about program safety. STEINBACH: |> Let B be a subclass of A, and let MyMethod be a virtual |> method declared in A and overridden or implemented in B. The B |> implementation of MyMethod may assume a properly constructed B |> object. If MyMethod is called virtually from an A constructor the |> assumptions in the B implementation may be invalid. The result |> may be a crash, unexpected behavior or incorrect construction |> causing problems later on. This is not uncommon in Java. KANZE: You said it. In my experience, it is one of the more frequent causes of errors in Java. STEINBACH: |> In C++, during execution of the body of an A constructor the object |> is, for purposes of virtual calls, an A object, even if the A |> constructor is executed as part of a B object construction. This |> is not the same as disallowing virtual calls from a constructor, |> and it's not the same as statically bound calls. But it means |> that direct or indirect calls from a constructor cannot be |> overridden by a subclass. KANZE: Correct. STEINBACH: |> 2 How can I achieve "virtual construction" in C++? |> |> Assume a class MyClass. Basically there are two ways of achieving |> virtual construction for MyClass: |> |> a In-class virtual call: "Two-stage construction." |> MyClass provides a virtual initialization method which must |> be called immediately after instantiating a MyClass object. |> |> b Out-of-class virtual call: "Parts-constructor." |> An object or function pointer (the parts-constructor) is |> passed to the MyClass constructor, which calls it. |> |> Both methods can benefit from encapsulation in an *object factory* |> (also called a "class factory"): |> |> c "Object factory" |> A class MyClassFactory with a function named "New", "Create" or |> something similar that handles all details of creating an object |> of MyClass. MyClassFactory will typically be a singleton. |> |> For method (a) the factory function encapsulates the call to the |> virtual initialization method. |> |> For method (b) the factory function is responsible for passing an |> appropriate parts-constructor (object or function) to the MyClass |> constructor. In most cases MyClassFactory can itself be the |> parts constructor. If MyClass is at the top of a class hierarchy |> then MyClassFactory may then be at the top of a corresponding |> parallel factory / parts constructor class hierarchy. KANZE: As a general rule (with a lot of exceptions), constructors should be simple, for several reasons: - If the object is really complex, "construction" can probably fail in unexceptional cases. So you need a return code, which the constructor itself cannot give you. - It may be necessary to construct an object before all of the necessary data is available. The most frequent case of this is when the object is a sub-object of another object -- in this case, it *must* be constructed before entering the constructor of the containing object. This fact argues for keeping the constructor as simple as possible, and using an initialization function to do the actual work. In many cases, this should be encapsulated in a factory method -- I tend to prefer static member functions for this. In such cases, the constructor should be declared either private or protected, in order to prevent instantiation other than in the factory method. In considering your options, you should also consider Scott Meyer's rule of never deriving from a concrete class -- the problem shouldn't arise in the first place. (Regrettably, I find that this rule is also only a general rule, and has a certain number of exceptions.) Finally, I'm not really sure what you mean by b), but in a few very specific cases, I've been able to use intelligent objects as constructor arguments, and call the initialization function from their destructor. With the correct constructors (implicit conversion), the user need not even be aware of the intermediary object. _______________________________________________ cpptips mailing list http://cpptips.hyperformix.com