5.8 Κληρονομικότητα (Inheritance) και Πολυμορφισμός (Polymorphism) στη γλώσσα C#

Η κληρονομικότητα (inheritance) και ο πολυμορφισμός (polymorphism) είναι δύο βασικές έννοιες στη γλώσσα C# που επιτρέπουν την οργάνωση και την αποδοτική ανάπτυξη των προγραμμάτων.

Η κληρονομικότητα είναι η δυνατότητα μιας κλάσης να κληρονομεί τα χαρακτηριστικά (μεταβλητές και μεθόδους) μιας άλλης κλάσης. Μια κλάση που κληρονομείται ονομάζεται υποκλάση, ενώ η κλάση που δίνει την κληρονομικότητα ονομάζεται γονική κλάση. Οι υποκλάσεις μπορούν να κληρονομήσουν τα χαρακτηριστικά της γονικής κλάσης και να προσθέσουν νέα χαρακτηριστικά ή να τροποποιήσουν τη συμπεριφορά των υπάρχοντων. Αυτό επιτρέπει την αναδιάρθρωση του κώδικα, την αποφυγή της επανάληψης και την αποδοτική αναπαραγωγή των κλάσεων.

Ο πολυμορφισμός αφορά τη δυνατότητα ενός αντικειμένου να λειτουργεί ως πολλαπλοί τύποι. Συγκεκριμένα, ένα αντικείμενο μπορεί να αντιμετωπίζεται ως αντικείμενο μιας γονικής κλάσης ή ως αντικε

ίμενο μιας υποκλάσης της. Αυτό επιτρέπει τη δημιουργία γενικών μεθόδων που μπορούν να εργαστούν με αντικείμενα που ανήκουν σε διάφορους τύπους. Ο πολυμορφισμός συνδέεται στενά με την κληρονομικότητα καθώς οι υποκλάσεις μπορούν να υλοποιούν διαφορετικές συμπεριφορές για τις ίδιες μεθόδους που έχουν κληρονομηθεί από τη γονική κλάση.

Η κληρονομικότητα και ο πολυμορφισμός αποτελούν σημαντικές αρχές της αντικειμενοστραφούς προγραμματισμού (OOP) που επιτρέπουν την οργάνωση και την ευελιξία του κώδικα, καθιστώντας την ανάπτυξη και τη συντήρηση προγραμμάτων πιο αποτελεσματική.

Στη γλώσσα προγραμματισμού C#, μπορούμε να χρησιμοποιήσουμε την κληρονομικότητα για τη μετάδοση πεδίων και μεθόδων από μια κλάση σε μια άλλη. Η κληρονομικότητα βασίζεται στην έννοια της “παράγωγης κλάσης” και της “βασικής κλάσης”:

  1. Παράγωγη κλάση (child): Αυτή είναι η κλάση που κληρονομεί την λειτουργικότητα από μια άλλη κλάση. Η παράγωγη κλάση μπορεί να επωφεληθεί από τα πεδία και τις μεθόδους της βασικής κλάσης.
  2. Βασική κλάση (parent): Αυτή είναι η κλάση που παρέχει τη λειτουργικότητά της στις παράγωγες κλάσεις. Η βασική κλάση ορίζει τα πεδία και τις μεθόδους που είναι κοινές για τις παράγωγες κλάσεις.

Για να πραγματοποιήσετε κληρονομικότητα σε μια κλάση, χρησιμοποιείτε το σύμβολο “:” (άνω κάτω τελεία). Η δήλωση κληρονομικότητας ακολουθείται από το όνομα της βασικής κλάσης από την οποία κληρονομείτε.

Παράδειγμα:

class ChildClass : ParentClass
{
    // Πρόσθετη λειτουργικότητα για την παράγωγη κλάση
}

Στο παραπάνω παράδειγμα, η κλάση ChildClass κληρονομεί τη λειτουργικότητα από την κλάση ParentClass. Μπορείτε να προσθέσετε πρόσθετα πεδία και μέθοδοι στην ChildClass, επωφελούμενοι από την κληρονομημένη λειτουργικότητα της ParentClass.

Ένα παράδειγμα κληρονομικότητας μεταξύ δύο κλάσεων μπορεί να είναι το εξής:

using System;

class Vehicle
{
    protected string brand; // Προστατευμένο πεδίο brand

    public void Honk()
    {
        Console.WriteLine("Beep beep!"); // Εκτύπωση μηνύματος στην οθόνη
    }
}

class Car : Vehicle // Κληρονομικότητα, η κλάση Car κληρονομεί την κλάση Vehicle
{
    private string modelName; // Ιδιωτικό πεδίο modelName

    static void Main(string[] args)
    {
        Car myCar = new Car(); // Δημιουργία ενός αντικειμένου της κλάσης Car με τη χρήση του κατασκευαστή

        myCar.brand = "Ford"; // Ανάθεση τιμής στο πεδίο brand του αντικειμένου myCar
        myCar.modelName = "Mustang"; // Ανάθεση τιμής στο πεδίο modelName του αντικειμένου myCar

        Console.WriteLine($"Brand: {myCar.brand}, Model: {myCar.modelName}"); // Εκτύπωση των τιμών των πεδίων brand και modelName του αντικειμένου myCar
        myCar.Honk(); // Κλήση της μεθόδου Honk() του αντικειμένου myCar
    }
}

Ο παραπάνω κώδικας σε C# ορίζει δύο κλάσεις, την κλάση Vehicle και την κλάση Car, και περιέχει μια μέθοδο Main ως σημείο εκκίνησης του προγράμματος.

Η κλάση Vehicle διαθέτει ένα προστατευμένο πεδίο με την ονομασία brand και μια μέθοδο Honk() που εκτυπώνει το μήνυμα “Beep beep!”.

Η κλάση Car κληρονομεί την κλάση Vehicle και διαθέτει ένα ιδιωτικό πεδίο modelName.

Η μέθοδος Main είναι η μέθοδος που εκτελείται κατά την έναρξη του προγράμματος. Σε αυτήν την μέθοδο, δημιουργείται ένα αντικείμενο της κλάσης Car με τη χρήση του κατασκευαστή. Στη συνέχεια, ορίζονται τιμές στα πεδία brand και modelName του αντικειμένου και εκτυπώνονται αυτές οι τιμές μέσω της μεθόδου Console.WriteLine(). Τέλος, καλείται η μέθοδος Honk() του αντικειμένου για να εκτελεστεί η ενέργεια του “κόρναρίσματος”.

Ουσιαστικά, ο κώδικας δημιουργεί ένα αντικείμενο αυτοκινήτου, ορίζει τη μάρκα και το μοντέλο του αυτοκινήτου, και εκτυπώνει αυτές τις πληροφορίες στην οθόνη. Στη συνέχεια, το αυτοκίνητο “κορνάρει”.

[adinserter block=”2″]

Εάν δεν θέλετε άλλες κλάσεις να κληρονομούν από μια κλάση, χρησιμοποιήστε τη λέξη-κλειδί sealed:

sealed class MyClass
{
    // Κώδικας κλάσης
}

Στο παραπάνω παράδειγμα, η κλάση MyClass ορίζεται ως sealed, που σημαίνει ότι δεν επιτρέπεται η κληρονομικότητα από άλλες κλάσεις. Οποιαδήποτε προσπάθεια να κληρονομηθεί η MyClass θα προκαλέσει ένα σφάλμα στον μεταγλωττιστή.

Η χρήση της λέξης-κλειδί sealed προσδιορίζει έναν τελικό τύπο, που δεν μπορεί να λειτουργήσει ως βασική κλάση για άλλες κλάσεις. Αυτό μπορεί να είναι χρήσιμο όταν θέλετε να περιορίσετε την κληρονομικότητα σε μια κλάση και να διασφαλίσετε ότι ο τύπος διατηρεί την αρχική του λειτουργία χωρίς περαιτέρω επεκτάσεις ή παραμορφώσεις.

Ο πολυμορφισμός (polymorphism) αναφέρεται στην “πολλαπλότητα των μορφών” και συμβαίνει όταν έχουμε πολλές κλάσεις που σχετίζονται μεταξύ τους μέσω κληρονομικότητας.

Όπως αναφέραμε και στο προηγούμενο κεφάλαιο, η κληρονομικότητα μας επιτρέπει να κληρονομήσουμε πεδία και μεθόδους από μια άλλη κλάση. Ο πολυμορφισμός χρησιμοποιεί αυτές τις μεθόδους για να εκτελέσει διάφορες εργασίες. Αυτό μας επιτρέπει να εκτελούμε μια ενέργεια με διαφορετικούς τρόπους.

Ένα παράδειγμα πολυμορφισμού είναι η υπερσυνάρτηση (overriding) μεθόδων. Όταν μια κλάση κληρονομεί μια μέθοδο από μια βασική κλάση, μπορεί να υπερκαλύψει (override) αυτήν τη μέθοδο για να παρέχει μια νέα υλοποίηση. Αυτό μας επιτρέπει να χρησιμοποιούμε τη μέθοδο με διαφορετικό τρόπο στην παράγωγη κλάση.

Για παράδειγμα, ας υποθέσουμε μια βασική κλάση με το όνομα Animal που έχει μια μέθοδο με το όνομα animalSound(). Οι παράγωγες κλάσεις των Animals θα μπορούσαν να είναι Pigs, Cats, Dogs, Birds και θα είχαν επίσης τη δική τους υλοποίηση για τον ήχο του ζώου (το γουρούνι κρούει, η γάτα νιαουρίζει, κλπ.):

using System;

class Animal
{
    // Ορισμός της εικονικής μεθόδου animalSound()
    public virtual void animalSound()
    {
        Console.WriteLine("The animal makes a sound");
    }
}

class Pig : Animal
{
    // Υλοποίηση της μεθόδου animalSound() για το γουρούνι
    public override void animalSound()
    {
        Console.WriteLine("The pig says: Oink oink!");
    }
}

class Cat : Animal
{
    // Υλοποίηση της μεθόδου animalSound() για τη γάτα
    public override void animalSound()
    {
        Console.WriteLine("The cat says: Meow!");
    }
}

class Dog : Animal
{
    // Υλοποίηση της μεθόδου animalSound() για το σκυλί
    public override void animalSound()
    {
        Console.WriteLine("The dog says: Woof woof!");
    }
}

class Bird : Animal
{
    // Υλοποίηση της μεθόδου animalSound() για το πουλί
    public override void animalSound()
    {
        Console.WriteLine("The bird says: Chirp chirp!");
    }
}

[adinserter block=”3″]

Ο παραπάνω κώδικας σε C# ορίζει μια ιεραρχία κλάσεων που αντιπροσωπεύει ζώα και κάθε ζώο έχει μια μέθοδο που περιγράφει τον ήχο που κάνει. Ακολουθούν τα βασικά στοιχεία του κώδικα:

  • Η κλάση Animal είναι η βασική κλάση που ορίζει τη μέθοδο animalSound() ως εικονική (virtual). Αυτό σημαίνει ότι οι υποκλάσεις μπορούν να αντικαταστήσουν τη μέθοδο αυτή για να παρέχουν διαφορετική υλοποίηση.
  • Οι κλάσεις Pig, Cat, Dog και Bird είναι υποκλάσεις της κλάσης Animal και αντικαθιστούν τη μέθοδο animalSound() με δικές τους υλοποιήσεις. Κάθε υποκλάση περιέχει τη μέθοδο animalSound() που εκτυπώνει έναν διαφορετικό ήχο για κάθε ζώο.

Όταν δημιουργείται ένα αντικείμενο από μια από τις υποκλάσεις (π.χ., Pig pig = new Pig();), μπορεί να κληθεί η μέθοδος animalSound() για να εκτυπωθεί ο αντίστοιχος ήχος που κάνει το ζώο. Για παράδειγμα:

Pig pig = new Pig();
Cat cat = new Cat();
Dog dog = new Dog();
Bird bird = new Bird();

pig.animalSound();  // Θα εκτυπωθεί: "The pig says: Oink oink!"
cat.animalSound();  // Θα εκτυπωθεί: "The cat says: Meow!"
dog.animalSound();  // Θα εκτυπ

ωθεί: "The dog says: Woof woof!"
bird.animalSound(); // Θα εκτυπωθεί: "The bird says: Chirp chirp!"

Έτσι, ο κώδικας προσδιορίζει τη συμπεριφορά και τον ήχο των διάφορων ζώων μέσω της κληρονομικότητας και της υλοποίησης εικονικών μεθόδων.

Τώρα μπορούμε να δημιουργήσουμε αντικείμενα Pig και Dog και να καλέσουμε τη μέθοδο animalSound() σε κάθε ένα από αυτά:

Pig myPig = new Pig();
Dog myDog = new Dog();

myPig.animalSound(); // Εκτυπώνει "The pig says: Oink oink!"
myDog.animalSound(); // Εκτυπώνει "The dog says: Woof woof!"

Σε αυτό το παράδειγμα, δημιουργούμε ένα αντικείμενο Pig με το όνομα myPig και ένα αντικείμενο Dog με το όνομα myDog. Στη συνέχεια, καλούμε τη μέθοδο animalSound() σε κάθε ένα από αυτά τα αντικείμενα. Η μέθοδος που εκτελείται είναι η υλοποίηση της αντίστοιχης κλάσης (Pig ή Dog), παράγοντας τον αντίστοιχο ήχο για κάθε ζώο.

21 Αυγούστου, 2023
top
error: Content is protected !!
Μετάβαση σε γραμμή εργαλείων