# Base Class Initialization
When a class inherits another class, Kotlin guarantees that both classes are properly initialized.
Kotlin creates valid objects by ensuring that constructors are called:
- Constructors for member objects.
- Constructors for new objects added in the derived class.
- The constructor for the base class.
In the [Inheritance](javascript:void(0)) examples, the base classes didn’t have constructor parameters. If a base class does have constructor parameters, a derived class must provide those arguments during construction.
Here’s the first GreatApe
example, rewritten with constructor parameters:
// BaseClassInit/GreatApe3.kt
package baseclassinit
import atomictest.eq
open class GreatApe(
val weight: Double,
val age: Int
)
open class Bonobo(weight: Double, age: Int) :
GreatApe(weight, age)
class Chimpanzee(weight: Double, age: Int) :
GreatApe(weight, age)
class BonoboB(weight: Double, age: Int) :
Bonobo(weight, age)
fun GreatApe.info() = "wt: $weight age: $age"
fun main() {
GreatApe(100.0, 12).info() eq
"wt: 100.0 age: 12"
Bonobo(110.0, 13).info() eq
"wt: 110.0 age: 13"
Chimpanzee(120.0, 14).info() eq
"wt: 120.0 age: 14"
BonoboB(130.0, 15).info() eq
"wt: 130.0 age: 15"
}
When inheriting from GreatApe
, you must pass the necessary constructor arguments to the GreatApe
base class, otherwise you’ll get a compile-time error message.
After Kotlin creates memory for your object, it calls the base-class constructor first, then the constructor for the next-derived class, and so on until it reaches the most-derived constructor. This way, all constructor calls can rely on the validity of all the sub-objects created before them. Indeed, those are the only things it knows about; a Bonobo
knows it inherits from GreatApe
and the Bonobo
constructor can call functions in the GreatApe
class, but a GreatApe
cannot know whether it’s a Bonobo
or a Chimpanzee
, or call functions specific to those subclasses.
When inheriting from a class you must provide arguments to the base-class constructor after the base class name. This calls the base-class constructor during object construction:
// BaseClassInit/NoArgConstructor.kt
package baseclassinit
open class SuperClass1(val i: Int)
class SubClass1(i: Int) : SuperClass1(i)
open class SuperClass2
class SubClass2 : SuperClass2()
When there are no base-class constructor parameters, Kotlin still requires empty parentheses after the base class name, to call that constructor without arguments.
If there are secondary constructors in the base class you may call one of those instead:
// BaseClassInit/House.kt
package baseclassinit
import atomictest.eq
open class House(
val address: String,
val state: String,
val zip: String
) {
constructor(fullAddress: String) :
this(fullAddress.substringBefore(", "),
fullAddress.substringAfter(", ")
.substringBefore(" "),
fullAddress.substringAfterLast(" "))
val fullAddress: String
get() = "$address, $state $zip"
}
class VacationHouse(
address: String,
state: String,
zip: String,
val startMonth: String,
val endMonth: String
) : House(address, state, zip) {
override fun toString() =
"Vacation house at $fullAddress " +
"from $startMonth to $endMonth"
}
class TreeHouse(
val name: String
) : House("Tree Street, TR 00000") {
override fun toString() =
"$name tree house at $fullAddress"
}
fun main() {
val vacationHouse = VacationHouse(
address = "8 Target St.",
state = "KS",
zip = "66632",
startMonth = "May",
endMonth = "September")
vacationHouse eq
"Vacation house at 8 Target St., " +
"KS 66632 from May to September"
TreeHouse("Oak") eq
"Oak tree house at Tree Street, TR 00000"
}
When VacationHouse
inherits from House
it passes the appropriate arguments to the primary House
constructor. It also adds its own parameters startMonth
and endMonth
—you aren’t limited by the number, type or order of the parameters in the base class. Your only responsibility is to provide the correct arguments in the call to the base-class constructor.
You call an overloaded base-class constructor by passing the matching constructor arguments in the base-class constructor call. You see this in the definitions of VacationHouse
and TreeHouse
. Each calls a different base-class constructor.
Inside a secondary constructor of a derived class you can either call the base-class constructor or a different derived-class constructor:
// BaseClassInit/OtherConstructors.kt
package baseclassinit
import atomictest.eq
open class Base(val i: Int)
class Derived : Base {
constructor(i: Int) : super(i)
constructor() : this(9)
}
fun main() {
val d1 = Derived(11)
d1.i eq 11
val d2 = Derived()
d2.i eq 9
}
To call the base-class constructor, use the super
keyword, passing the constructor arguments as if it is a function call. Use this
to call another constructor of the same class.
Exercises and solutions can be found at www.AtomicKotlin.com.