I am maintaining some Java 8 code which looks like this:
Class Entity {
protected Model theModel;
public Entity() {
init();
}
protected void init() {
this.theModel = new Model();
}
}
Class Model {
}
Class SubModel extends Model {
}
main {
Entity newEntity = new Entity() {
#Override
protected void init() {
this.theModel = new SubModel();
}
};
}
The code currently compiles and runs correctly, but I now need to update it.
My question are:
How is the override of the init() method working at all, during the construction of the newEntity?
What is the correct terminology for this method override included in the object constructor statement?
My research so far suggests that Java cannot dynamically override methods - cannot do overrides on this basis, because method overrides are per-class not per-object. But this code snippet seems to show that Java can do it in practice?
UPDATE: Note that the creation of the newEntity in main creates an anonymous sub-class, and the init() method is being overridden for that anonymous sub-class only. This is explained better in the two excellent answers below.
As far as I can tell there is nothing special here, is just classical constructor chaining and polymorphism applied to virtual method invocations.
When you instantiate your anonymous class, it will automatically invoke its default constructor (which is automatically given by the compiler), before its default constructor succeeds it must first invoke its parent class default constructor, which in turn will invoke the init() method, which, since it has been overridden by your anonymous class, polymorphically, ends up calling the init method in the child class, which initializes the model to your SubModel instance.
Joshua Bloch has a few interesting arguments against this pattern in his famous book Effective Java, in the section "Item 17: Design and document for inheritance or else prohibit" he wrote:
“There are a few more restrictions that a class must obey to allow
inheritance. Constructors must not invoke overridable methods,
directly or indirectly. If you violate this rule, program failure will
result. The superclass constructor runs before the subclass
constructor, so the overriding method in the subclass will get invoked
before the subclass constructor has run. If the overriding method
depends on any initialization performed by the subclass constructor,
the method will not behave as expected. To make this concrete, here's
a class that violates this rule:”
He then proceeds to give an example which you would do well to study:
“Here's a subclass that overrides the overrideMe, method which is
erroneously invoked by Super's sole constructor:”
public class Super {
// Broken - constructor invokes an overridable method
public Super() {
overrideMe();
}
public void overrideMe() {
}
}
public final class Sub extends Super {
private final Date date; // Blank final, set by constructor
Sub() {
date = new Date();
}
// Overriding method invoked by superclass constructor
#Override public void overrideMe() {
System.out.println(date);
}
public static void main(String[] args) {
Sub sub = new Sub();
sub.overrideMe();
}
}
“You might expect this program to print out the date twice, but it
prints out null the first time, because the overrideMe method is
invoked by the Super constructor before the Sub constructor has a
chance to initialize the date field. Note that this program observes a
final field in two different states! Note also that if overrideMe had
invoked any method on date, the invocation would have thrown a
NullPointerException when the Super constructor invoked overrideMe.
The only reason this program doesn't throw a NullPointerException as
it stands is that the println method has special provisions for
dealing with a null argument.”
So, as you can see, and as Joshua Bloch explained so well, the risks lurk in the shadows: in the possibilities of what you can do in the overridden method, where you have license to touch instance variables that the constructor chain has not yet had a chance to initialize. The point is that you should not be allowed to touch the object state until it has been fully initialized by the constructor chain.
You might say that in your particular case that does not happen, since you are not illegally altering state and your overridden method is protected, not public, but the problem is that any person touching this code needs a very clear understanding of all these things happening under the hood, happening in places other than your current code. During maintenance it is easy to make a serious mistake, particularly when you or some other developer, comes back here to make changes, possibly months or even years after this was originally defined, and having lost context of all these dangers somebody introduces a bug that will be really hard to find and fix.
If it is in fact exactly as you are showing us, and there is no significant part of the picture missing, then the code that you have to maintain is bad, and maintenance of bad code is very troublesome.
Invoking an overridable from within a constructor is legal, but it is very bad practice, because the overridable will be invoked on a descendant whose constructor has not yet been invoked, which is catastrophic. It may not matter in trivial examples, where descendants have empty constructors, but it is bound to cause major trouble later, when things become more complicated, and a descendant suddenly one day needs to have a non-empty constructor.
And with the passage of time things do tend to become more complicated.
A halfway decent IDE would have issued a big fat warning on the invocation of the overridable from within the constructor. This in turn means that the code was written with an insufficient number of warnings enabled, which probably means that it is full of problems of this kind.
The correct terminology for this method override included in the object constructor is: Wrong.
You cannot correct this without some major refactoring. Either the model needs to be passed as a constructor parameter, or the constructor must live with the fact that the model cannot be known at all during construction.
Your question about "dynamically" overriding methods is a bit strange, and it is probably unnecessarily complicating things. Virtual method dispatching is done internally by means of a virtual method table. Each class has its own virtual method table, which never changes. However, when a constructor executes, the this pointer points to the actual (descendant) instance, so the virtual method table in effect is that of the descendant. So, when the constructor calls an overridable, the overridable of the descendant is invoked.
That's different from C++, where the virtual method table in effect at construction time is the virtual method table of the class declaring the constructor, (irrespective of whether it has been subclassed,) so when you call a virtual method from within a C++ constructor you are not invoking any overriding methods.
Related
Consider this code (complete class, runs fine, all classes in one class for the sake of brevity).
My questions are after the code listing:
import java.util.LinkedList;
import java.util.List;
class Gadget {
public void switchon() {
System.out.println("Gadget is Switching on!");
}
}
interface switchonable {
void switchon();
}
class Smartphone extends Gadget implements switchonable {
#Override
public void switchon() {
System.out.println("Smartphone is switching on!");
}
}
class DemoPersonnel {
public void demo(Gadget g) {
System.out.println("Demoing a gadget");
}
public void demo(Smartphone s) {
System.out.println("Demoing a smartphone");
}
}
public class DT {
/**
* #param args
*/
public static void main(String[] args) {
List<Gadget> l = new LinkedList<Gadget>();
l.add(new Gadget());
l.add(new Smartphone());
for (Gadget gadget : l) {
gadget.switchon();
}
DemoPersonnel p = new DemoPersonnel();
for (Gadget gadget : l) {
p.demo(gadget);
}
}
}
Questions:
From the compilers point of view, what is the origin of the switchon method in Smartphone? Is it inherited from the base class Gadget? Or is it an implementation of the switchon method mandated by the switchonable interface? Does the annotation make any difference here?
In the main method, first loop: Here, we see a case of runtime polymorphism - i.e., when the first for loop is running, and gadget.switchon() is called, it first prints "Gadget is switching on", and then it prints "Smartphone is switching on". But in the second loop, this runtime resolution does not happen, and the output for both calls to demo is "Demoing a gadget", whereas I was expecting it to print "Demoing a gadget" the first iteration, and "Demoing a smartphone" the second time.
What am I understanding wrong? Why does the runtime resolve the child class in the first for loop, but doesn't do so in the second for loop?
Lastly, a link to a lucid tutorial on runtime/compile-time polymorphism in Java will be appreciated. (Please do not post the Java tutorial trail links, I didn't find the material particularly impressive when discussing the finer nuances in respectable depth).
This is how it works shortly:
Compiling time
The compiler defines the required signature for the requested method
Once the signature is defined, the compiler starts to look for it in the type-Class
If it finds any compatible candidate method with the required signature proceeds, otherwise returns an error
Runtime
During execution JVM starts to look for the candidate method with the signature as exactly defined during the compiling-time.
The search for the executable method actually starts from the real Object implementation Class (which can be a subclass of the type-Class) and surf the whole hierarchy up.
Your List is defined with type Gadget.
for (Gadget gadget : l) {
gadget.switchon();
}
When you ask for gadget.switchon(); the compiler will look for the switchon() method in the Gadget class and as it's there the candidate signature is simply confirmed to be switchon().
During the execution, the JVM will look for a switchon() method from the Smartphone Class and this is why it is displaying the correct message.
Here is what happens in the second for-loop
DemoPersonnel p = new DemoPersonnel();
for (Gadget gadget : l) {
p.demo(gadget);
}
The signature in this case is for both objects demo(Gadget g), this is why for both iterations method demo(Gadget g) is executed.
Hope it helps!
From the compilers point of view, what is the origin of the switchon method in Smartphone? Is it inherited from the base class Gadget? Or is it an implementation of the switchon method mandated by the switchonable interface?
The second case
Does the annotation make any difference here?
Not at all, #Override is just a helper, whe you use it you are telling the compiler: "my intention is to override the method from a supertype, please throw an exception and don't compile this if it is not overriding anything"
About the second question, in this case the method that better match acording to its signature is the one to be called. At run time in the second loop your objects have the supertype "associated", that's the reason public void demo(Gadget g) will be called rather than public void demo(Smartphone g)
1.It shouldn't matter. Because it is extending Gadget, if you don't override and call switchon() from a smartphone, it would say "Gadget is switching on!". When you have both an interface and a parent class with the same method, it really doesn't matter.
2.The first loop works and the second doesn't because of the way java looks at objects. When you call a method from an object, it takes the method directly from that object, and thus knows whether smartphone or gadget. When you send either a Smartphone or Gadget into an overloaded method, everything in that class is called a Gadget, whether it is actually a smartphone or not. Because of this, it uses the gadget method. To make this work, you would want to use this in the demo(Gadget g) method of DemoPersonnel:
if(gadget instanceof Smartphone){
System.out.println("Demoing a gadget");
}else{
System.out.println("Demoing a smartphone");
}
Sorry I don't have a link to a tutorial, I learned through a combination of AP Computer Science and experience.
Answering question 2 first: In the second loop your passing an object typed as a Gadget therefore the best match in the demo class is the method taking a gadget. this is resolved a compile time.
for question 1: the annotation does not make a difference. it just indicates that you overriding (implementing) method in the interface.
For compiler, Smartphone inherits switchon() method "implementation" from Gadget and then Smartphone overrides inherited implementation with its own implementation. On the other hand switchonable interface dictates Smartphone to provide an implementation of switchon() method definition and which was fulfilled by the implementation overridden in Smartphone.
First case is working as you expected because it is indeed a case of polymorphism i.e. you have one contract and two implementations - one in Gadget and another in Smartphone; where later has "overridden" the former implementation. Second case "should not" work as you expect it to, because there's only one contract and one implementation. Do note that you are "not overriding" the demo() method, you are actually "overloading" the demo() method. And, overloading means two "different" unique method definitions that only shares the "same name". So, it is a case of one contract and one implementation, when you call demo() with Gadget parameter, because compiler will match the method name with exact method parameter type(s) and by doing so will call "different methods" in both iterations of the loop.
about the second question :
In Java, dynamic method dispatch happens only for the object the method is called on, not for the parameter types of overloaded methods.
Here is a link to the java language specification.
As it says :
When a method is invoked (§15.12), the number of actual arguments (and
any explicit type arguments) and the compile-time types of the
arguments are used, at compile time, to determine the signature of the
method that will be invoked (§15.12.2). If the method that is to be
invoked is an instance method, the actual method to be invoked will be
determined at run time, using dynamic method lookup (§15.12.4).
so basically :the compile time type of the method parameters is used to determine the signature of the method to be called
At runtime, the class of the object the method is called on determines which implementation of that method is called, taking into account that it may be an instance of a subclass of the declared type that overrides the method.
In your case when you create object of a child class by new child(); and pass it on to the overloaded method, it has superclass type associated. Hence overloaded method with parent's object is called.
The annotation does not make any difference here. Techinically is like you are doing both things: overriding parent switchon() and implementing the switchon() interface method in one shot.
Method lookup (with respect to method arguments) is not done dynamically (at runtime) but statically at compile-time. Looks strange but thats how it works.
Hope this helps.
The compiler selects a method signature based on the declared type of the "this" pointer for the method and the declared type of the parameters. So since switchon receives a "this" pointer of Gadget, that is the version of the method that the compiler will reference in its generated code. Of course, runtime polymorphism can change that.
But runtime polymorphism only applies to the method's "this" pointer, not the parms, so the compiler's choice of method signature will "rule" in the second case.
Like so?
abstract public class BaseTask extends Runnable {
public BaseTask(ParamA aParam) {
// do something with aParam
StaticExecutorService.submit(this);
}
}
public class AbcTask extends BaseTask {
public ABC(ParamA aParam, ParamB bParam) {
super(aParam);
}
#Override
public void run() {
}
}
The class can then just be created and queued for execution by doing a
new AbcTask();
I'm not sure if this is ok because maybe it is still being constructed when ExecutorService decides to execute AbcTask?
If you don't recommend this for whatever reason, please state and elaborate.
Thanks
This might work (at least, I'm not familiar enough with Java to see why it wouldn't), but I would not recommend it as it introduces too strong a coupling: AbcTask would be tied to StaticExecutorService and would be less reusable than it could easily be. This will also make the AbcTask harder to test and debug.
Also, you're "overloading" the meaning of object construction by folding submission to an executor into it. What if, later on, you decide you want to do something to AbcTask objects in between constructing them and submitting them?
We should not use this until the constructor is completed.
An object is instantiated fully after completion of it's c'tor. so the object passed within StaticExecutorService might not be created fully and may not be usable.
I don't know if specification supports my above statement. but i feel so.
Hence, acc. to me it should be avoided.
Its tightly coupled
In Effective Java, Joshua Bloch explained why it is not a good practice to invoke a protected/public method from a constructor. See 2nd edition, CH-4: Constructors must not invoke overridable methods, directly or indirectly.
StaticExecutorService.submit(this);
Above line will invoke the public method run from the constructor, and this is not expected.
Explanation from the book: Constructors must not invoke overridable methods, directly or indirectly
If you violate this rule, program failure will result. The superclass constructor runs
before the subclass constructor, so the overriding method in the subclass will get
invoked before the subclass constructor has run. If the overriding method depends
on any initialization performed by the subclass constructor, the method will not
behave as expected.
In your example it will probably work but as the call to super() has to be the first in child classes of BaseTask this means that the constructor won't be able to perform any operation before the submission of the task.
From you sample, the second parameter cannot be used since the task will be submitted before you can assign it to an attribute.
If we consider the following code:
public class MyTask extends BaseTask {
public ABC(ParamA aParam, String name) {
super(aParam);
this.name = name == null ? "Default Value" : name;
}
#Override
public void run() {
System.out.println("Name length: "+ name.length());
}
}
Since run() can be called before the assignment of this.name the System.out line can end in NullPointerException
I do know the syntactical difference between overriding and overloading. And I also know that overriding is run-time polymorphism and overloading is compile-time polymorphism. But my question is: "Is overloading is really compile-time polymorphism? Is the method call really solving at compile time?". To clarify my point, let's consider an example class.
public class Greeter {
public void greetMe() {
System.out.println("Hello");
}
public void greetMe(String name) {
System.out.println("Hello " + name);
}
public void wishLuck() {
System.out.println("Good Luck");
}
}
Since all of the methods greetMe(), greetMe(String name), wishLuck() are public, they all can be overriden(including overloaded one), right? For example,
public class FancyGreeter extends Greeter {
public void greetMe() {
System.out.println("***********");
System.out.println("* Hello *");
System.out.println("***********");
}
}
Now, consider the following snippet:
Greeter greeter = GreeterFactory.getRandomGreeter();
greeter.greetMe();
The getRandomGreeter() method returns a random Greeter object. It may either return an object of Greeter, or any of its subclasses, like FancyGreeter or GraphicalGreeter or any other one. The getRandomGreeter() will create the objects either using new or dynamically load the class file and create object using reflection(I think it is possible with reflection) or any other way that is possible. All of these methods of Greeter may or may not be overriden in subclasses. So the compiler has no way to know whether a particular method(overloaded or not) is overriden. Right? Also, wikipedia says on Virtual functions:
In Java, all non-static methods are by default "virtual functions".
Only methods marked with the keyword final, which cannot be overridden,
along with private methods, which are not inherited, are non-virtual.
Since, virtual functions are resolved at run-time using dynamic method dispatch, and since all non private, non final methods are virtual(whether overloaded or not), they must be resolved at run-time. Right?
Then, How can overloading still be resolved at compile-time? Or, is there anything that I misunderstood, or am I missing?
Every 'Greeter' class has 3 virtual methods: void greetMe(), void greetMe(String), and void wishLuck().
When you call greeter.greetMe() the compiler can work out which one of the three virtual methods should be called from the method signature - ie. the void greetMe() one since it accepts no arguments. Which specific implementation of the void greetMe() method is called depends on the type of the greeter instance, and is resolved at run-time.
In your example it's trivial for the compiler to work out which method to call, since the method signatures are all completely different. A slightly better example for showing the 'compile time polymorphism' concept might be as follows:
class Greeter {
public void greetMe(Object obj) {
System.out.println("Hello Object!");
}
public void greetMe(String str) {
System.out.println("Hello String!");
}
}
Using this greeter class will give the following results:
Object obj = new Object();
String str = "blah";
Object strAsObj = str;
greeter.greetMe(obj); // prints "Hello Object!"
greeter.greetMe(str); // prints "Hello String!"
greeter.greetMe(strAsObj); // prints "Hello Object!"
The compiler will pick out the method with the most specific match using the compile-time type, which is why the 2nd example works and calls the void greetMe(String) method.
The last call is the most interesting one: Even though the run-time type of strAsObj is String, it has been cast as an Object so that's how the compiler sees it. So, the closest match the compiler can find for that call is the void greetMe(Object) method.
Overloaded methods can still be overridden, if that is what you ask.
Overloaded methods are like different families, even though they share the same name. The compiler statically chooses one family given the signature, and then at run time it is dispatched to the most specific method in the class hierarchy.
That is, method dispatching is performed in two steps:
The first one is done at compile time with the static information available, the compiler will emit a call for the signature that matches best your current method parameters among the list of overloaded methods in the declared type of the object the method is invoked upon.
The second step is performed at run time, given the method signature that should be called (previous step, remember?), the JVM will dispatch it to the most concrete overridden version in the actual type of receiver object.
If the method arguments types are not covariant at all, overloading is equivalent to having methods names mangled at compile time; because they are effectively different methods, the JVM won't never ever dispatch them interchangeably depending on the type of the receiver.
What is polymorphism?
Acc. to me: if an entity can be represented in more than one forms, that entity is said to exhibit polymorphism.
Now, lets apply this definition to Java constructs:
1) Operator overloading is compile time polymorphism.
For example, + operator can be used to add two numbers OR to concatenate two strings. it's an example of polymorphism strictly saying compile-time polymorphism.
2) Method overloading is compile time polymorphism.
For example, a method with same name can have more than one implemntations. it's also a compile-time polymorphism.
It's compile-time because before execution of program compiler decides the flow of program i.e which form will be used during run-time.
3) Method overriding is run-time polymorphism.
For example, a method with same signature can have more than one implemenations. it's a run time polymorphism.
4) Base class use in place of derived class is run time polymorphism.
For example, an interface reference can point to any of it's implementor.
It's run-time because the flow of program can't be known before execution i.e. only during run-time it can be decided that which form will be used.
I hope it clears a bit.
Overloading in this respect means that the type of the function is statically determined at compile time as opposed to dynamic dispatch.
What really happens behind the scenes is that for a method named "foo" with types "A" and "B" two methods are created ("foo_A" and "foo_B"). Which of them is to be called is determined at compile-time (foo((A) object) or foo((B) object) result in foo_A being called or foo_B). So in a way this is compile-time polymorphism, although the real method (i.e. which implementation in the class hierarchy to take) is determined at runtime.
I have strong objection to call method overloading as compile time polymorphism.
I agree that method overloading is static binding(compile time) but i didn't see polymorphism in that.
I tried to put my opinion in my question to get clarification. you can refer this link.
We always say that method overloading is static polymorphism and overriding is runtime polymorphism. What exactly do we mean by static here? Is the call to a method resolved on compiling the code? So whats the difference between normal method call and calling a final method? Which one is linked at compile time?
Method overloading means making multiple versions of a function based on the inputs. For example:
public Double doSomething(Double x) { ... }
public Object doSomething(Object y) { ... }
The choice of which method to call is made at compile time. For example:
Double obj1 = new Double();
doSomething(obj1); // calls the Double version
Object obj2 = new Object();
doSomething(obj2); // calls the Object version
Object obj3 = new Double();
doSomething(obj3); // calls the Object version because the compilers see the
// type as Object
// This makes more sense when you consider something like
public void myMethod(Object o) {
doSomething(o);
}
myMethod(new Double(5));
// inside the call to myMethod, it sees only that it has an Object
// it can't tell that it's a Double at compile time
Method Overriding means defining a new version of the method by a subclass of the original
class Parent {
public void myMethod() { ... }
}
class Child extends Parent {
#Override
public void myMethod() { ... }
}
Parent p = new Parent();
p.myMethod(); // calls Parent's myMethod
Child c = new Child();
c.myMethod(); // calls Child's myMethod
Parent pc = new Child();
pc.myMethod(); // call's Child's myMethod because the type is checked at runtime
// rather than compile time
I hope that helps
Your are right - calls to overloaded methods are realized at compile time. That's why it is static.
Calls to overridden methods are realized at run-time, based on the type on which the method is invoked.
On virtual methods wikipedia says:
In Java, all non-static methods are by default "virtual functions." Only methods marked with the keyword final are non-virtual.
final methods cannot be overridden, so they are realized statically.
Imagine the method:
public String analyze(Interface i) {
i.analyze();
return i.getAnalysisDetails();
}
The compiler can't overload this method for all implementations of Interface that can possibly be passed to it.
I don't think you can call overloading any sort of polymorphism. Overloaded methods are linked at compile time, which kind of precludes calling it polymorphism.
Polymorphism refers to the dynamic binding of a method to its call when you use a base class reference for a derived class object. Overriding methods is how you implement this polymorphic behaviour.
i agree with rachel, because in K&B book it is directly mentioned that overloading does not belong to polymorphism in chapter 2(object orientation). But in lots of places i found that overloading means static polymorphism because it is compile time and overriding means dynamic polymorphism because it s run time.
But one interesting thing is in a C++ book (Object-Oriented Programming in C++ - Robert Lafore) it is also directly mentioned that overloading means static polymorphism.
But one more thing is there java and c++ both are two different programing languages and they have different object manipulation techniques so may be polymorphism differs in c++ and java ?
Method Overloading simply means providing two separate methods in a class with the same name but different arguments while method return type may or may not be different which allows us to reuse the same method name.
But both methods are different hence can be resolved by compiler at compile time that's is why it is also known as Compile Time Polymorphism or Static Polymorphism
Method Overriding means defining a method in the child class which is already defined in the parent class with same method signature i.e same name, arguments and return type.
Mammal mammal = new Cat();
System.out.println(mammal.speak());
At the line mammal.speak() compiler says the speak() method of reference type Mammal is getting called, so for compiler this call is Mammal.speak().
But at the execution time JVM knows clearly that mammal reference is holding the reference of object of Cat, so for JVM this call is Cat.speak().
Because method call is getting resolved at runtime by JVM that's why it is also known as Runtime Polymorphism and Dynamic Method Dispatch.
Difference Between Method Overloading and Method Overriding
For more details, you can read Everything About Method Overloading Vs Method Overriding.
Simple Definition - Method overloading deals with the notion of having two or more methods(functions) in the same class with the same name but different arguments.
While Method overriding means having two methods with the same arguments, but different implementation. One of them would exist in the Parent class (Base Class) while another will be in the derived class(Child Class).#Override annotation is required for this.
Check this :
Click here for a detailed example
Property Over-loading Overriding
Method Names -------------->must be Same----------------must be same
Arg Types------------------>must be Different(at least arg)
Method Signature
Return Type
Private,Static,Final
Access Modifier
try/Catch
Method Resolution
First, I want to discuss Run-time/Dynamic polymorphism and Compile-time/static polymorphism.
Compile-time/static polymorphism:- as its name suggests that it bind the function call to its appropriate Function at compile time. That means the compiler exactly know which function call associated to which function. Function overloading is an example of compile time polymorphism.
Run-time/Dynamic polymorphism:-In this type of polymorphism compiler don't know which functions call associates to which function until the run of the program. Eg. function overriding.
NOW, what are the function overriding and function overloading???
Function Overloading:- same function name but different function signature/parameter.
eg. Area(no. of parameter)
{ -------------
----------------
return area;}
area of square requires only one parameter
area of rectangle requires two parameters(Length and breadth)
function overriding:- alter the work of a function which is present in both the Superclass and Child class.
eg. name() in superclass prints "hello Rahul" but after overring in child class it prints "hello Akshit"
Tried to cover all differences
Overloading Overriding
Method Name Must be same Must be same
Argument Types Must be same Must be different
Return Type No restriction Must be same till 1.4V
but after 1.4V
co- variants
were introduced
private/static/final Can be overloaded Cannot be overridden
Access Modifiers No restriction Cannot reduce the scope
Throws keyword No restriction If child class method
throws a checked
exception the parent
class method must throw
the same or the
parent exception
Method Resolution Taken care by compiler Taken care by JVM based
based on reference types on run-time object
Known as Compile-Time Polymorphism, RunTime Polymorphism,
Static Polymorphism, or dynamic polymorphism,
early binding late binding.
I know that calling a virtual method from a base class constructor can be dangerous since the child class might not be in a valid state. (at least in C#)
My question is what if the virtual method is the one who initializes the state of the object ? Is it good practice or should it be a two step process, first to create the object and then to load the state ?
First option: (using the constructor to initialize the state)
public class BaseObject {
public BaseObject(XElement definition) {
this.LoadState(definition);
}
protected abstract LoadState(XElement definition);
}
Second option: (using a two step process)
public class BaseObject {
public void LoadState(XElement definition) {
this.LoadStateCore(definition);
}
protected abstract LoadStateCore(XElement definition);
}
In the first method the consumer of the code can create and initialize the object with one statement:
// The base class will call the virtual method to load the state.
ChildObject o = new ChildObject(definition)
In the second method the consumer will have to create the object and then load the state:
ChildObject o = new ChildObject();
o.LoadState(definition);
(This answer applies to C# and Java. I believe C++ works differently on this matter.)
Calling a virtual method in a constructor is indeed dangerous, but sometimes it can end up with the cleanest code.
I would try to avoid it where possible, but without bending the design hugely. (For instance, the "initialize later" option prohibits immutability.) If you do use a virtual method in the constructor, document it very strongly. So long as everyone involved is aware of what it's doing, it shouldn't cause too many problems. I would try to limit the visibility though, as you've done in your first example.
EDIT: One thing which is important here is that there's a difference between C# and Java in order of initialization. If you have a class such as:
public class Child : Parent
{
private int foo = 10;
protected override void ShowFoo()
{
Console.WriteLine(foo);
}
}
where the Parent constructor calls ShowFoo, in C# it will display 10. The equivalent program in Java would display 0.
In C++, calling a virtual method in a base class constructor will simply call the method as if the derived class doesn't exist yet (because it doesn't). So that means that the call is resolved at compile time to whatever method it should call in the base class (or classes it derived from).
Tested with GCC, it allows you to call a pure virtual function from a constructor, but it gives a warning, and results in a link time error. It appears that this behavior is undefined by the standard:
"Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (class.virtual) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined."
With C++ the virtual methods are routed through the vtable for the class that is being constructed. So in your example it would generate a pure virtual method exception since whilst BaseObject is being constructed there simply is no LoadStateCore method to invoke.
If the function is not abstract, but simply does nothing then you will often get the programmer scratching their head for a while trying to remember why it is that the function doesn't actually get called.
For this reason you simply can't do it this way in C++ ...
For C++ the base constructor is called before the derived constructor, which means that the virtual table (which holds the addresses of the derived class's overridden virtual functions) does not yet exist. For this reason, it is considered a VERY dangerous thing to do (especially if the functions are pure virtual in the base class...this will cause a pure-virtual exception).
There are two ways around this:
Do a two-step process of construction + initialization
Move the virtual functions to an internal class that you can more closely control (can make use of the above approach, see example for details)
An example of (1) is:
class base
{
public:
base()
{
// only initialize base's members
}
virtual ~base()
{
// only release base's members
}
virtual bool initialize(/* whatever goes here */) = 0;
};
class derived : public base
{
public:
derived ()
{
// only initialize derived 's members
}
virtual ~derived ()
{
// only release derived 's members
}
virtual bool initialize(/* whatever goes here */)
{
// do your further initialization here
// return success/failure
}
};
An example of (2) is:
class accessible
{
private:
class accessible_impl
{
protected:
accessible_impl()
{
// only initialize accessible_impl's members
}
public:
static accessible_impl* create_impl(/* params for this factory func */);
virtual ~accessible_impl()
{
// only release accessible_impl's members
}
virtual bool initialize(/* whatever goes here */) = 0;
};
accessible_impl* m_impl;
public:
accessible()
{
m_impl = accessible_impl::create_impl(/* params to determine the exact type needed */);
if (m_impl)
{
m_impl->initialize(/* ... */); // add any initialization checking you need
}
}
virtual ~accessible()
{
if (m_impl)
{
delete m_impl;
}
}
/* Other functionality of accessible, which may or may not use the impl class */
};
Approach (2) uses the Factory pattern to provide the appropriate implementation for the accessible class (which will provide the same interface as your base class). One of the main benefits here is that you get initialization during construction of accessible that is able to make use of virtual members of accessible_impl safely.
For C++, section 12.7, paragraph 3 of the Standard covers this case.
To summarize, this is legal. It will resolve to the correct function to the type of the constructor being run. Therefore, adapting your example to C++ syntax, you'd be calling BaseObject::LoadState(). You can't get to ChildObject::LoadState(), and trying to do so by specifying the class as well as the function results in undefined behavior.
Constructors of abstract classes are covered in section 10.4, paragraph 6. In brief, they may call member functions, but calling a pure virtual function in the constructor is undefined behavior. Don't do that.
If you have a class as shown in your post, which takes an XElement in the constructor, then the only place that XElement could have come from is the derived class. So why not just load the state in the derived class which already has the XElement.
Either your example is missing some fundamental information which changes the situation, or there's simply no need to chain back up to the derived class with the information from the base class, because it has just told you that exact information.
i.e.
public class BaseClass
{
public BaseClass(XElement defintion)
{
// base class loads state here
}
}
public class DerivedClass : BaseClass
{
public DerivedClass (XElement defintion)
: base(definition)
{
// derived class loads state here
}
}
Then your code's really simple, and you don't have any of the virtual method call problems.
For C++, read Scott Meyer's corresponding article :
Never Call Virtual Functions during Construction or Destruction
ps: pay attention to this exception in the article:
The problem would almost certainly
become apparent before runtime,
because the logTransaction function is
pure virtual in Transaction. Unless it
had been defined (unlikely, but
possible) the program wouldn't link: the linker would be unable to find the necessary implementation of Transaction::logTransaction.
Usually you can get around these issues by having a greedier base constructor. In your example, you're passing an XElement to LoadState. If you allow the state to be directly set in your base constructor, then your child class can parse the XElement prior to calling your constructor.
public abstract class BaseObject {
public BaseObject(int state1, string state2, /* blah, blah */) {
this.State1 = state1;
this.State2 = state2;
/* blah, blah */
}
}
public class ChildObject : BaseObject {
public ChildObject(XElement definition) :
base(int.Parse(definition["state1"]), definition["state2"], /* blah, blah */) {
}
}
If the child class needs to do a good bit of work, it can offload to a static method.
In C++ it is perfectly safe to call virtual functions from within the base-class - as long as they are non-pure - with some restrictions. However, you shouldn't do it. Better initialize objects using non-virtual functions, which are explicitly marked as being such initialization functions using comments and an appropriate name (like initialize). If it is even declared as pure-virtual in the class calling it, the behavior is undefined.
The version that's called is the one of the class calling it from within the constructor, and not some overrider in some derived class. This hasn't got much to-do with virtual function tables, but more with the fact that the override of that function might belong to a class that's not yet initialized. So this is forbidden.
In C# and Java, that's not a problem, because there is no such thing as a default-initialization that's done just before entering the constructor's body. In C#, the only things that are done outside the body is calling base-class or sibling constructors i believe. In C++, however, initializations done to members of derived classes by the overrider of that function would be undone when constructing those members while processing the constructor initializer list just before entering the constructors body of the derived class.
Edit: Because of a comment, i think a bit of clarification is needed. Here's an (contrived) example, let's assume it would be allowed to call virtuals, and the call would result in an activation of the final overrider:
struct base {
base() { init(); }
virtual void init() = 0;
};
struct derived : base {
derived() {
// we would expect str to be "called it", but actually the
// default constructor of it initialized it to an empty string
}
virtual void init() {
// note, str not yet constructed, but we can't know this, because
// we could have called from derived's constructors body too
str = "called it";
}
private:
string str;
};
That problem can indeed be solved by changing the C++ Standard and allowing it - adjusting the definition of constructors, object lifetime and whatnot. Rules would have to be made to define what str = ...; means for a not-yet constructed object. And note how the effect of it then depends on who called init. The feature we get does not justify the problems we have to solve then. So C++ simply forbids dynamic dispatch while the object is being constructed.