Reputation: 13
I'll keep this as simple as possible. Let's say I have a parent class with a function as below that takes a position argument as a Point data class
open class Obj(val pos:Point) {
fun foo() : Double {
return 5.0 + pos.x * pos.y * pos.z
}
}
For sake of thoroughness, here is the Point data class
data class Point(val x:Double, val y:Double, val z:Double)
So I have multiple children that inherit from the Obj class but implement an additional function that is named the same in every child and calls a function in the parent,
class Cube(pos:Point) : Obj(pos) {
fun number() : Double {
return 10.0 * foo()
}
}
class Sphere(pos:Point) : Obj(pos) {
fun number() : Double {
return 20.0 * foo()
}
}
My question is, if I have a function somewhere that takes in objects that inherit from Obj but not Obj itself, how can I ensure they are of their own subtype rather than the Supertype?
For example, I currently have my function looking like this
fun foo2(obj:Obj) {
println(obj.number()) // throws error because obj doesn't have method number()
}
Upvotes: 1
Views: 59
Reputation: 13
Okay so using the suggestion from Animesh Sahu, I've implemented an Interface called ObjI in the base class, and required each implementation override the number() function. I combined that with the answer given by gidds, suggesting creating a function that calls another function. So the number() function in the base class just calls the foo() function
data class Point(val x:Double, val y:Double, val z:Double)
interface ObjI {
fun number() : Double
}
open class Obj(val p:Point) : ObjI {
override fun number() = foo()
fun foo() : Double {
return 5.0 + p.x * p.y * p.z
}
}
class Sphere(p:Point) : Obj(p) {
override fun number() : Double {
return 10.0 * super.foo()
}
}
class Cube(p:Point) : Obj(p) {
override fun number() : Double {
return 20.0 * super.foo()
}
}
fun main(args: Array<String>) {
val s = Sphere(Point(13.0, 6.0, 1.0))
val c = Cube(Point(13.0, 6.0, 1.0))
printem(s)
printem(c)
}
fun printem(o:Obj) {
println(o.number())
}
Upvotes: 0
Reputation: 18627
The normal approach to this sort of case would be to add an abstract method to the base class, and have the subclasses implement it. That way, whenever you have a base class reference, the compiler knows that method is available.
That would require the base class itself to be abstract, so you can't instantiate it directly. (And if foo()
is only used by number()
implementations, it might make sense to hide it from other classes.)
abstract class Obj(val pos: Point) {
abstract fun number(): Double
protected fun foo() = 5.0 + pos.x * pos.y * pos.z
}
class Cube(pos: Point) : Obj(pos) {
override fun number() = 10.0 * foo()
}
If, however, you need the base class to be instantiable, then that's more tricky: there's no easy way to specify 'only subclasses'. Depending on your exact requirements, you might allow the base class to be passed, and have it provide a default implementation of number()
:
open fun number() = foo()
Upvotes: 0