Inheriting non-implicit constructors on Apex classes

If I have an abstract parent class like this:

abstract class Vehicle {
    public Vehicle(Person driver) {
        //
    }
}

and then I create a child class like this:

public class MagicCarpet extends Vehicle {
    //this won't compile
}

I encounter the following Compile Error:

Error: Parent class has no 0-argument constructor for implicit construction at line … column …

Obviously I can explicitly re-declare a constructor on the child class toget it to compile:

public class MagicCarpet extends Vehicle {
    public MagicCarpet(Person driver) {
        super(driver);
    }
}

But I feel this isn’t DRY. Not sure what’s actually going on under the covers here.

How can I get a constructor (other than the implicit 0-argument one) to be inherited by a child class?

Answer

As in Java, Apex constructors are not members that can be inherited:

A subclass inherits all the members (fields, methods, and nested
classes) from its superclass. Constructors are not members, so they
are not inherited by subclasses, but the constructor of the superclass
can be invoked from the subclass.

http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

Constructors are not inherited, but their execution is always chained such that the “most super” class constructor is executed first and the constructor for the class that you are explicitly constructing is called last.

Try running this anonymous code block (note – class definitions in anonymous blocks are virtual by default):

public class ClassOne { ClassOne() { system.debug('1'); } }
public class ClassTwo extends ClassOne { ClassTwo() { system.debug('2'); } }
public class ClassThree extends ClassTwo { ClassThree() { system.debug('3'); } }
ClassThree c = new ClassThree();

Here’s a part of my debug log:

14:04:26.065 (65211131)|EXECUTION_STARTED
14:04:26.065 (65225442)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
14:04:26.072 (72618936)|SYSTEM_CONSTRUCTOR_ENTRY|[4]|<init>()
14:04:26.072 (72699003)|SYSTEM_CONSTRUCTOR_ENTRY|[3]|<init>()
14:04:26.072 (72787259)|SYSTEM_CONSTRUCTOR_ENTRY|[2]|<init>()
14:04:26.072 (72884681)|USER_DEBUG|[1]|DEBUG|1
14:04:26.072 (72902439)|SYSTEM_CONSTRUCTOR_EXIT|[2]|<init>()
14:04:26.072 (72920871)|USER_DEBUG|[2]|DEBUG|2
14:04:26.072 (72932472)|SYSTEM_CONSTRUCTOR_EXIT|[3]|<init>()
14:04:26.072 (72947553)|USER_DEBUG|[3]|DEBUG|3
14:04:26.072 (72958530)|SYSTEM_CONSTRUCTOR_EXIT|[4]|<init>()

This is quite important. It allows the subclass to be ignorant of the implementation of the superclass and guarantees to the author of the superclass that it will have an opportunity to initialise itself before it is used, even if constructed by an unknown subclass constructor (which may or may not have arguments). (As Peter says in his answer, if you don’t call super explicitly it will be called implicitly).

To preserve the chain, the compiler will also provide a default 0-argument constructor so long as you don’t provide any constructors yourself:

If you write a constructor that takes arguments, you can then use that
constructor to create an object using those arguments. If you create a
constructor that takes arguments, and you still want to use a
no-argument constructor, you must include one in your code. Once you
create a constructor for a class, you no longer have access to the
default, no-argument public constructor. You must create your own.

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_constructors.htm

Which also means that having created a constructor in an abstract/virtual class which takes an argument, you must also provide a 0-argument constructor in order to extend the class – hence your build error.

Chaining of constructors then is quite different from inheritance of member methods; It doesn’t feel to me like it would be right to be able to mix the two.


I have blogged a slightly fuller answer here: http://foobarforce.com/2014/03/06/constructors/

Attribution
Source : Link , Question Author : Matt and Neil , Answer Author : Stephen Willcock

Leave a Comment