2

Possible Duplicate:
Why do we not have a virtual constructor?

I know this has been asked before but I didn't understand the complex technical words used in the other answers.

I read on a community the reason that constructors cannot be virtual is

The ‘virtual’ mechanism works on a logically complete (completely constructed) object. We know that we use constructors to logically initialize our objects. In other words, the object is not completely constructed until the constructor has finished executing. Thus, we can’t have virtual constructors.

There is a misconception that by then virtual table is incomplete so we can’t have virtual constructors. Just before the constructor starts executing the virtual table is properly constructed and the ‘this’ pointer passed to the constructors. Moreover, virtual table mechanism is implementation depended, and finds no place in the C++ standard. And hence, to argue over this issue using the virtual table concept is illogical.

Now, as the constructor finishes executing any other function can be virtual. Destructor is no exception to this rule as it is a function. Virtual destructors are required in case we use a base class pointer to refer to a derived class object, use it, and then delete it. If we have virtual destructor, using ‘delete’, a chain of destructors is called starting from the derived to the base. But, had there been no ‘virtual’ in destructor only the base class destructor is called (and not the derived). This (may) generate inconsistencies in the program.

Is the above reason correct? The answer doesn't talk about the static and dynamic types of objects.

Community
  • 1
  • 1
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345

4 Answers4

6

Virtual constructors don't make sense and aren't necessary. The only time you call a constructor is when creating an object. You need to know the type of an object in order to create it, so the static and dynamic types are the same, and the correct constructor to call is the one for that type.

That's why they aren't necessary. Why they don't make sense, is that when creating an object, base class constructors are called as well as derived class constructors. If the base class constructor was overridden in the derived class, is that supposed to mean that the base class constructor isn't called after all?

Other languages have virtual constructors, perhaps because constructors in those languages are methods, and they only have virtual invocation for non-static methods. But those other languages (Java and Python spring to mind) have to introduce special rules that constructors must/should construct their base class explicitly as a call from the constructor. C++ just does it (perhaps in an initializer list, if the base class constructor requires parameters), using non-virtual constructors, and there is no option to enter the body of the constructor with uninitialized base class sub objects.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • But algebraic types in functional programming use the equivalent of virtual constructors all the time (just have a look at the `Maybe` monad), and there exists a (convoluted) solution via factory methods to implement this in languages that don’t support them. So I’d say that they make sense and are necessary. – Konrad Rudolph Sep 29 '10 at 10:42
  • @Konrad: I can't comment on functional languages, whether their model of a constructor is similar enough to C++'s model of a constructor, that the same analysis applies. As far as virtual factory methods go, it's *occasionally* useful for a class to have the virtual constructor idiom `clone` and `create` non-static member functions, in addition to regular constructors. I don't think it's necessary to build that into every object, although Java's use of the `Cloneable` interface as a flag to enable it is fairly nifty.Not sure if CRTP can achieve the same in C++ without convolution... – Steve Jessop Sep 29 '10 at 10:49
  • @Steve: you must be the last person to describe `Cloneable` as nifty – everyone else has reached the consensus that this interface is a [complete](http://stackoverflow.com/questions/709380/java-rationale-of-the-cloneable-interface/709438#709438) and utter [disaster](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4098033), and to use [other solutions](http://www.artima.com/intv/bloch13.html) instead. – Konrad Rudolph Sep 29 '10 at 10:53
  • 1
    @Konrad: I said "nifty", not "perfect" ;-p The nifty part is just that you use the interface to mark the class for copying by the VM. The fact that `clone` is a protected method of `Object` is not nifty. If Java had mixins, `Cloneable` would be one, would provide a public default implementation of `clone`, and then would basically just work (although perhaps should have separate deep_clone and shallow_clone interfaces). But apparently multiple inheritance is evil, so Java sleeps in the bed it made... – Steve Jessop Sep 29 '10 at 10:57
  • @Steve Jessop: When a public clone method is useful, an implementation-provided meberwise clone is the soundest basis for it. The "confusion" about deep versus shallow seems unwarranted. Many of the types where cloning would be useful are generic containers; the natural behavior for cloning a container would be to clone as deeply as necessary as to preserve the semantics of the *container*, but don't clone the objects contained therein. Where's the ambiguity? – supercat Feb 17 '11 at 19:09
  • @supercat: I agree shallow is "natural", but depth of cloning becomes an issue even with containers. If you have a container of references to containers (which is what Java has) then sometimes you'd *want* to copy the inner containers and sometimes not, depending in your particular example whether you're using them as if they were a unified structure or not. How do you clone a 2-d array? Naturally the rows of the copy should be copes of the rows of the original. Now what about a vector of vectors? Naturally the inner vectors should be the identical objects... – Steve Jessop Feb 17 '11 at 22:35
  • ... so the semantics of the two are different. Deep vs shallow still doesn't express all possibilities, so I think both are useful tools to implement in the language, but still don't cover all cases. At root I think it's bad to encourage people to implement functions with the same name (`clone`) that do completely different things on different classes. If it's obviously going to be a member-wise clone, call it `memberwise_clone`. In C++ it's in some ways easier than Java simply because containers contain values not references, so copy ctors and assignment operators are rarely confusing at all. – Steve Jessop Feb 17 '11 at 22:41
  • @Steve Jessop: Certainly there are cases where specialized or recursive collections may benefit from separate deep and shallow cloning, but I wouldn't call that the "general" case. While there aren't a whole lot of cases where it's useful to know something is cloneable without knowing what it is, cloning methods based upon the root Clone can be relied upon to return an object of the original type. If SomeObject implements clone via some other way, and DerivedObject inherits from SomeObject but doesn't implement Clone, calling Clone on a DerivedObject will yield odd results. – supercat Feb 17 '11 at 22:46
  • @supercat: I agree with that, and inheriting `clone` is tricksy in some of the ways that inheriting `equals` is tricksy: it's fundamental that equality of different types is difficult to define correctly. I've forgotten what I'm supposed to be arguing now, but when I said "should have separate interfaces", I meant that if the language is going to help with cloning then it should help with both, separately, and make clear the difference with different names. I didn't mean that a typical class would want to enable both. – Steve Jessop Feb 17 '11 at 22:49
  • @Steve Jessop: If a class is *semantically described* as a vector of vectors, cloning the object should clone the inner vectors. If a structure is defined as vector of things, and those things simply happen to be vectors, cloning the outer object should not clone the things therein. I'll admit it would be nice if there were a standardized DeepClone interface, which primitive and immutable semi-primitive (e.g. String) types supported, but that doesn't imply that semantic-level cloning isn't useful. – supercat Feb 17 '11 at 22:50
  • @supercat: Sure. If you're writing a library vector, you're describing it as a vector of things, so shallow clone is appropriate and should be provided. You also know darn well your users will compose containers, so they'll find two things useful: a full deep clone (which you can provide by calling `clone` recursively), and also a clone to whatever depth they happen to consider their semantic structure in that usage (which you can't sanely provide). Intermediate cloning is fine for less generic classes, but where semantics aren't utterly obvious, I'd say keep off the name `clone` is all. – Steve Jessop Feb 17 '11 at 22:58
  • Example - if I pass a factory into an object, I'm not sure whether a clone of the object should use a clone of the factory. It's really up to the user whether they pass the same factory to lots of different objects (in which case they probably don't want it cloned) or create a factory for each object (in which case they probably do), and I don't think there's any natural, intuitive answer. So you just document it. In C++ you do have a clue in that clone behavior probably follows resource ownership. – Steve Jessop Feb 17 '11 at 23:08
  • @Steve Jessop: If I'm writing a generic container object, I would expect that it's likely that at some point it will be used to hold objects that people want to clone--true. I would say that the proper way to achieve that would be for someone to create a class SomeCloneableThingList which inherits from e.g. List(Of SomeCloneableThing), and overrides the Clone method to first call the base (List) clone method and then call an appropriate clone method on each thing in the list. – supercat Feb 18 '11 at 00:08
  • @supercat: you could do that, but it violates LSP because your `clone` method visibly doesn't do the same thing as the `clone` method of the parent class. Which is why I say that inheriting clone is tricksy. – Steve Jessop Feb 18 '11 at 10:23
  • @Steve Jessop: I see your point; this reinforces my earlier-expressed (elsewhere) belief that clone methods for inheritable classes should be Protected, and a cloning interface should be generic with regard to its base class, include a Self property to return that base class. At least in current .net languages, that would allow code to ask for either a CloneableList(of T) or an ICloneable(of List(Of T)), depending upon whether it wanted the exact CloneableList class, or a cloneable derivative of List(Of T). – supercat Feb 18 '11 at 17:10
  • @Steve Jessop: I haven't seen it done often, but I think the pattern of having a non-inheritable class derive from a class for the purpose of adding an interface can be a helpful concept. For example, a DuffleBag collection may be thread-safe, but one might imagine useful derivatives of it not being thread-safe. In that case, one might have a DuffleBag collection which implements IDuffleBag, and a ThreadSafeDuffleBag collection which inherits from it and is essentially identical except that it implements IThreadSafeDuffleBag, which in turn... – supercat Feb 18 '11 at 17:50
  • ...simply inherits IDuffleBag. In that way, people who need the thread-safety promise that the base DuffleBag could keep but derivatives might not could use IThreadSafeDuffleBag; those who don't need that promise could use IDuffleBag. – supercat Feb 18 '11 at 17:51
  • @supercat: Sounds reasonable. For another example, Symbian should have done that when it made its string classes and interfaces inherit from the corresponding immutable string classes and interfaces. Although arguably Symbian has enough string interfaces already, what it did does cause genuine confusion between the concepts of "non-modifiable by you" and "immutable" because the interface is really only the former whereas the 'corresponding' implementation actually is immutable, sort of. There's no interface for an immutable string. – Steve Jessop Feb 18 '11 at 18:48
  • @Steve Jessop: I've commented elsewhere that the proper design for a maybe-mutable class is to have interfaces IReadableFoo, IMutableFoo, IImmutableFoo, and possibly IWritableFoo. IReadableFoo would be the base, and the next two would inherit separately from it; IMutableFoo would also inherit from IWritableFoo. Too bad .net doesn't allow a read-only property and write-only property to be used together as a read-write property; the inconvenience of separate read, write, and read-write properties might make IWritableFoo a nuisance--too bad, since a covariant IWritableFoo would otherwise be nice. – supercat Feb 18 '11 at 19:33
3

To quote from The C++ Programming Language:

To construct an object, a constructor needs the exact type of the object it is to create. Consequently, a constructor cannot be virtual. Furthermore, a constructor is not quite an ordinary function. In particular, it interacts with memory management routines in ways ordinary member functions don’t. Consequently, you cannot have a pointer to a constructor.

It must be interesting to note that C++ do have an idiom called virtual constructor. You can read more about that here.

Vijay Mathew
  • 26,737
  • 4
  • 62
  • 93
1

Yes, the reason is you need to have a pointer/reference to a complete object already before you can call a virtual function. When the constructor is being invoked there's no complete object yet. Even more, when you do new SomeClass() you don't even have a pointer yet - the pointer is returned upon the new statement is completed successfully.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
1

The virtual keyword cannot be applied to a constructor since a constructor turns raw bits into a living object, and until there is a living object against which to invoke a member function, the member function cannot possibly work correctly. Instead of thinking of constructors as normal member functions on the object, imagine that they are static member functions that create objects. - C++ FAQs

josh
  • 13,793
  • 12
  • 49
  • 58