Are constructors guaranteed to be called first?
One of the things about constructors in C++ that makes them useful is that they're guaranteed to be called, to set up objects, before any member functions can be called. Therefore, member functions can rely on state to be set up right. Yes, there are a few nasty ways to run into some situations where this doesn't happen (static initializer problems come to mind) but it's fairly difficult.
Java took the idea of constructors for its use. After all, they're very handy. But the guarantee isn't there. And it hurts.
Take this simple Java program:
public class TestApp { public static void main(String[] args) { Child child = new Child(); } abstract static class Parent { Parent() { System.out.println("Parent.Parent"); abstractMethod(); } abstract void abstractMethod(); } static class Child extends Parent { Child() { System.out.println("Child.Child"); } void abstractMethod() { System.out.println("Child.abstractMethod"); } } }
What happens when you run it?
Parent.Parent Child.abstractMethod Child.Child
Java makes no guarantees about whether or not constructors are called before methods.
Try the same stunt with C++:
#include <iostream.h> class Parent { public: Parent() { cout << "Parent::Parent" << endl; abstractMethod(); } virtual void abstractMethod() = 0; }; class Child : Parent { public: Child() { cout << "Child::Child" << endl; } virtual void abstractMethod() { cout << "Child::abstractMethod" << endl; } }; int main() { Child* child = new Child(); }
and watch gcc tell you that you just can't do that:
TestApp.cpp: In constructor `Parent::Parent()': TestApp.cpp:10: error: abstract virtual `virtual void Parent::abstractMethod()' called from constructor
Now, of course, it's trivial to evade that warning:
class Parent { public: Parent() { cout << "Parent::Parent" << endl; callAbstractMethod(); } void callAbstractMethod() { abstractMethod(); } virtual void abstractMethod() = 0; };
and then you can watch your app croak:
pure virtual method called Parent::Parent Abort
So, take your pick. C++ is annoying at times, but tries its best to strongly ensure the validity of its object lifetime semantic. Java will let you do whatever you want with your objects. If you want to play with them before they're fully constructed, go ahead. Just watch out.
Comments
I think Java has a slightly different understanding of object lifetimes than you do. :) One important distinction between C++ and Java is that in C++ an object is not considered to be fully constructed until its constructor returns. If you throw an exception from a constructor that isn't caught inside the constructor, your object's destructor won't be invoked. Some compilers may delete the object's memory, but not all.
In Java, an object is fully constructed upon entrance of its constructor. So when you say 'new Child()' and you enter Parent's constructor, you already have a valid Child object. It's therefore possible to invoke methods on Child, as you've seen.
In any case, this isn't the only way to have a non-constructor method invoked before the code in the constructor is run. If you have a member variable mFoo in your object and it's initialized to the result of a method, that method will be invoked before any code inside the constructor.
Posted by: Eric Albert | September 9, 2004 5:06 AM
testing. will I get a "questionable content" error this time?
Posted by: morris | September 10, 2004 12:57 AM
OK, it's on for now. Anyway, I can't post code into this board, it's just too hard. Using angle brackets causes the post to get all mangled up on preview. If I use HTML entities instead, it'll preview fine - and I ASSUME post fine - but after one preview they're converted back to angle brackets and will screw up on the next occasion. And, to add insult to injury, just as I had it right my post was repeatedly rejected for "Questionable content". So no code example today, sorry.... and this comment script has some real issues. It might have had it's feelings hurt by me, I don't know, maybe that was the "questionable" part.
Anyway, suppose you have a class named A or something like that, with a method named B. Nothing in C++ stops you from declaring a variable "p" as type "A *" and calling B through p. Nothing at all! Except that it might crash if you actually need the "this" pointer. But not everything needs the "this" pointer - "hello world" wouldn't, for example.
And if you really feel guilty afterwards, you can set p equal to a "new A" and now you can have your constructor called - after the method. Isn't C++ fun?
Hope that none of this was too "questionable"....
morris
Posted by: morris | September 10, 2004 1:03 AM