Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

تجاوز الأعضاء

جزء من قسم البرمجة كائنية التوجه في رحلة Kotlin على Coddy. الدرس 18 من 57.

يمكن للفئة الفرعية استبدال طريقة موروثة بنسختها الخاصة. تحدد الفئة الفائقة الطريقة open، وتعلن الفئة الفرعية عنها مرة أخرى باستخدام override:

open class Animal(val name: String) {
    open fun sound() = "..."
}
class Dog(name: String) : Animal(name) {
    override fun sound() = "Woof"
}
class Cat(name: String) : Animal(name) {
    override fun sound() = "Meow"
}

داخل main:

println(Dog("Rex").sound())
println(Cat("Tom").sound())
println(Animal("Generic").sound())

الناتج:

Woof
Meow
...

يتم اختيار الإصدار الذي يتم تشغيله وفقًا للفئة الفعلية للكائن، حتى عندما يكون نوع المتغير هو الفئة الفائقة. كما أن التعليمة البرمجية داخل الفئة الفائقة التي تستدعي أسلوبًا مفتوحًا تحصل أيضًا على إصدار الفئة الفرعية:

open class Animal(val name: String) {
    open fun sound() = "..."
    fun speak() = "$name says ${sound()}"
}
class Dog(name: String) : Animal(name) {
    override fun sound() = "Woof"
}

داخل main:

val pets: List<Animal> = listOf(Dog("Rex"), Animal("Generic"))
for (p in pets) println(p.speak())

الناتج:

Rex says Woof
Generic says ...

يمكن تجاوز الخصائص بالطريقة نفسها: open val في الفئة الفائقة، وoverride val في الفئة الفرعية، سواء أكانت خاصية عادية أو خاصية مُعرَّفة في المُنشئ أو مُلحقًا محسوبًا:

open class Shape {
    open val name = "shape"
    open val corners = 0
}
class Triangle : Shape() {
    override val name = "triangle"
    override val corners = 3
}
class Polygon(override val corners: Int) : Shape() {
    override val name: String
        get() = "$corners-gon"
}

داخل main:

for (s in listOf(Shape(), Triangle(), Polygon(6))) println("${s.name}: ${s.corners}")

الناتج:

shape: 0
triangle: 3
6-gon: 6

العضو المحدد بالوسم override يصبح مفتوحًا مرة أخرى، لذا يمكن للفئة الفرعية للفئة الفرعية تجاوزه مرة أخرى؛ أما final override فيمنع ذلك. لا يمكن تجاوز العضو الذي لا يحتوي على open إطلاقًا، ولا يجوز للفئة الفرعية تعريف عضو بالتوقيع نفسه:

open class Animal {
    open fun sound() = "..."
    fun sleep() = "zzz"
}
open class Dog : Animal() {
    final override fun sound() = "Woof"
}
class Puppy : Dog() {
    // override fun sound() = "Yip"   // خطأ: 'sound' في 'Dog' نهائي
    // fun sleep() = "nap"            // خطأ: 'sleep' يخفي عضواً من الفئة الأساسية
}
challenge icon

التحدي

سهل

تحتوي Animal على legs() (4) وsound() (...) وdescribe()، التي تُرجع Rex has 4 legs and says Woof، وذلك بالاعتماد على legs() وsound(). اجعل legs() وsound() قابلتين لإعادة التعريف، وأكمل الأصناف الفرعية بإعادة تعريف هاتين الدالتين فقط: تقول Dog Woof، ولدى Bird ساقان وتقول Tweet، ولدى Snake 0 من الأرجل وتقول Hiss. تبقى describe() كما هي في Animal.

يقرأ الكود المُزوَّد الأسطر dog,Rex وbird,Pip وsnake,Kaa أو أي نوع آخر (أي Animal عادي)، ويخزّن الحيوانات في List<Animal> واحدة، ويطبع describe() لكل حيوان.

ضع الكود الخاص بك في Animal.kt وDog.kt وBird.kt وSnake.kt. يحتوي Main.kt على كود الإدخال/الإخراج المُزوَّد ولا يمكن تعديله.

جرّب بنفسك

fun main() {
    // كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
    val input = generateSequence(::readLine).toList()
    val animals = mutableListOf<Animal>()
    for (line in input) {
        val (kind, name) = line.split(",")
        animals.add(when (kind) {
            "dog" -> Dog(name)
            "bird" -> Bird(name)
            "snake" -> Snake(name)
            else -> Animal(name)
        })
    }
    for (a in animals) println(a.describe())
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: Playground لـ Kotlin