Megosztás a következőn keresztül:


Öröklés – típusok levezetése speciálisabb viselkedés létrehozásához

Az öröklődés a beágyazással és a polimorfizmussal együtt az objektumorientált programozás három fő jellemzője közé tartozik. Az öröklés lehetővé teszi, hogy olyan új osztályokat hozzon létre, amelyek újra felhasználják, kibővítik és módosítják a más osztályokban definiált viselkedést. Az az osztály, amelynek tagjai öröklődnek, alaposztálynak, a tagokat öröklő osztályt pedig származtatott osztálynak nevezzük. Egy származtatott osztálynak csak egy közvetlen alaposztálya lehet. Az öröklés azonban tranzitív. Ha ClassC származik ClassB-ből, és ClassB származik ClassA-ból, akkor ClassC örökli a ClassB-ben és ClassA-ban deklarált tagokat.

Megjegyzés:

A szerkezetek nem támogatják az öröklést, de interfészeket implementálhatnak.

Elméletileg a származtatott osztály az alaposztály specializációja. Például, ha van egy alap osztálya Animal, lehet egy származtatott osztály, amelyet Mammal-nek hívnak, és egy másik származtatott osztály, amelyet Reptile-nek hívnak. Az A Mammal egy Animal, az a Reptile pedig egy Animal, de minden származtatott osztály az alaposztály különböző specializációit jelöli.

A felületi deklarációk meghatározhatják a tagok alapértelmezett implementációját. Ezeket az implementációkat származtatott interfészek és az ezeket megvalósító osztályok öröklik. Az alapértelmezett felületi módszerekkel kapcsolatos további információkért tekintse meg a felületekről szóló cikket.

Amikor egy másik osztályból származtatott osztályt határoz meg, a származtatott osztály implicit módon nyeri az alaposztály összes tagját, kivéve annak konstruktorait és véglegesítőit. A származtatott osztály újra felhasználja a kódot az alaposztályban anélkül, hogy újra kellene azt használnia. További tagokat is felvehet a származtatott osztályba. A származtatott osztály kibővíti az alaposztály funkcióit.

Az alábbi ábrán egy olyan osztály WorkItem látható, amely valamilyen üzleti folyamat munkaelemét jelöli. Mint minden osztály, ez is a System.Object származik, és örökli annak metódusait. WorkItem saját hat taggal bővíti. Ezek a tagok konstruktort is tartalmaznak, mert a konstruktorok nem öröklődnek. Az ChangeRequest osztály WorkItem-ből örököl és egy adott típusú munkaelemet képvisel. ChangeRequest további két tagot ad hozzá azokhoz a tagokhoz, amelyeket WorkItem és Object örököl. Hozzá kell adnia saját konstruktort, és azt is hozzá kell adnia originalItemID. A tulajdonság originalItemID lehetővé teszi, hogy a ChangeRequest példány az eredetihez WorkItem legyen társítva, amelyre a módosítási kérelem vonatkozik.

Osztályöröklést bemutató diagram

Az alábbi példa bemutatja, hogy az előző ábrán bemutatott osztálykapcsolatok hogyan jelennek meg C#-ban. A példa azt is bemutatja, hogyan WorkItem bírálja felül a virtuális metódust Object.ToString, és hogy az ChangeRequest osztály hogyan örökli a WorkItem metódus implementációját. Az első blokk határozza meg az osztályokat:

// WorkItem implicitly inherits from the Object class.
public class WorkItem
{
    // Static field currentID stores the job ID of the last WorkItem that
    // has been created.
    private static int currentID;

    //Properties.
    protected int ID { get; set; }
    protected string Title { get; set; }
    protected string Description { get; set; }
    protected TimeSpan jobLength { get; set; }

    // Default constructor. If a derived class does not invoke a base-
    // class constructor explicitly, the default constructor is called
    // implicitly.
    public WorkItem()
    {
        ID = 0;
        Title = "Default title";
        Description = "Default description.";
        jobLength = new TimeSpan();
    }

    // Instance constructor that has three parameters.
    public WorkItem(string title, string desc, TimeSpan joblen)
    {
        this.ID = GetNextID();
        this.Title = title;
        this.Description = desc;
        this.jobLength = joblen;
    }

    // Static constructor to initialize the static member, currentID. This
    // constructor is called one time, automatically, before any instance
    // of WorkItem or ChangeRequest is created, or currentID is referenced.
    static WorkItem() => currentID = 0;

    // currentID is a static field. It is incremented each time a new
    // instance of WorkItem is created.
    protected int GetNextID() => ++currentID;

    // Method Update enables you to update the title and job length of an
    // existing WorkItem object.
    public void Update(string title, TimeSpan joblen)
    {
        this.Title = title;
        this.jobLength = joblen;
    }

    // Virtual method override of the ToString method that is inherited
    // from System.Object.
    public override string ToString() =>
        $"{this.ID} - {this.Title}";
}

// ChangeRequest derives from WorkItem and adds a property (originalItemID)
// and two constructors.
public class ChangeRequest : WorkItem
{
    protected int originalItemID { get; set; }

    // Constructors. Because neither constructor calls a base-class
    // constructor explicitly, the default constructor in the base class
    // is called implicitly. The base class must contain a default
    // constructor.

    // Default constructor for the derived class.
    public ChangeRequest() { }

    // Instance constructor that has four parameters.
    public ChangeRequest(string title, string desc, TimeSpan jobLen,
                         int originalID)
    {
        // The following properties and the GetNexID method are inherited
        // from WorkItem.
        this.ID = GetNextID();
        this.Title = title;
        this.Description = desc;
        this.jobLength = jobLen;

        // Property originalItemID is a member of ChangeRequest, but not
        // of WorkItem.
        this.originalItemID = originalID;
    }
}

Ez a következő blokk az alap- és származtatott osztályok használatát mutatja be:

// Create an instance of WorkItem by using the constructor in the
// base class that takes three arguments.
WorkItem item = new WorkItem("Fix Bugs",
                            "Fix all bugs in my code branch",
                            new TimeSpan(3, 4, 0, 0));

// Create an instance of ChangeRequest by using the constructor in
// the derived class that takes four arguments.
ChangeRequest change = new ChangeRequest("Change Base Class Design",
                                        "Add members to the class",
                                        new TimeSpan(4, 0, 0),
                                        1);

// Use the ToString method defined in WorkItem.
Console.WriteLine(item.ToString());

// Use the inherited Update method to change the title of the
// ChangeRequest object.
change.Update("Change the Design of the Base Class",
    new TimeSpan(4, 0, 0));

// ChangeRequest inherits WorkItem's override of ToString.
Console.WriteLine(change.ToString());
/* Output:
    1 - Fix Bugs
    2 - Change the Design of the Base Class
*/

Absztrakt és virtuális metódusok

Ha egy alaposztály egy metódust virtualdeklarál, a származtatott osztály saját implementációval is rendelkezhet override . Ha egy alaposztály tagként abstractdeklarál egy tagot, akkor ezt a metódust felül kell bírálni minden olyan nem absztrakt osztályban, amely közvetlenül örökli az adott osztályt. Ha egy származtatott osztály maga absztrakt, implementálás nélkül örökli az absztrakt tagokat. Az absztrakt és a virtuális tagok képezik a polimorfizmus alapját, amely az objektumorientált programozás második elsődleges jellemzője. További információ: Polimorfizmus.

Absztrakt alaposztályok

Az osztályokat absztraktként deklarálhatja, ha meg szeretné akadályozni a közvetlen példányosítást az új operátor használatával. Az absztrakt osztály csak akkor használható, ha egy új osztály származik belőle. Az absztrakt osztályok tartalmazhatnak egy vagy több olyan metódus-aláírást, amelyek maguk is absztraktként vannak deklarálva. Ezek az aláírások határozzák meg a paramétereket és a visszatérési értéket, de nincs implementációjuk (metódus törzse). Az absztrakt osztályoknak nem kell absztrakt tagokat tartalmazniuk; ha azonban egy osztály tartalmaz absztrakt tagot, akkor magát az osztályt absztraktként kell deklarálni. A nem absztrakt származtatott osztályoknak meg kell adniuk az absztrakt alaposztályból származó absztrakciós metódusok implementálását.

Felületek

Az interfész egy referenciatípus, amely meghatározza a tagok egy csoportját. Az interfészt megvalósító összes osztálynak és szerkezetnek implementálnia kell ezt a tagcsoportot. Egy felület meghatározhat egy alapértelmezett implementációt ezen tagok bármelyikéhez vagy mindegyikéhez. Egy osztály több interfészt is képes implementálni, annak ellenére, hogy csak egyetlen közvetlen alaposztályból származhat.

Az interfészek olyan osztályok adott képességeinek meghatározására szolgálnak, amelyek nem feltétlenül rendelkeznek "is a" kapcsolatokkal. Az interfészt például bármely osztály vagy szerkezet implementálhatja annak megállapításához, System.IEquatable<T> hogy a típus két objektuma egyenértékű-e (a típus azonban az egyenértékűséget határozza meg). IEquatable<T> nem azt sugallja, hogy ugyanaz a „van” típusú kapcsolat állna fenn, mint az alaposztály és a származtatott osztály között (például a Mammal egy Animal). További információ: Interfészek.

További származtatás megakadályozása

Egy osztály megakadályozhatja, hogy más osztályok örökölni tudjanak tőle vagy bármely tagjától, ha magát vagy tagját sealeddeklarálják.

Az alaposztálytagok származtatott osztálytagok általi elrejtése

A származtatott osztályok elrejthetik az alaposztálytagokat, ha azonos nevű és aláírású tagokat deklarálnak. A new módosító használatával egyértelműen jelezhető, hogy a tag nem szándékozik az alaptag felülbírálása lenni. A new használata nem kötelező, de a fordító figyelmeztetést készít, ha new nincs használatban. További információ: Verziószámozás felülbírálással és új kulcsszavakkal; valamint a felülbírálás és az új kulcsszavak használatának ismerete.