27 listopada 2013

[C++11] virtual, final, override

Klasa, która zawiera czysto wirtualną funkcję (= 0) jest klasą abstrakcyjną (nie da się stworzyć obiektu z takiej klasy).

Często klasy dziedziczące po klasie abstrakcyjnej zaczynały się od słowa virtual, choć nie jest to konieczne. Była to konwencja stosowana przez programistów, aby oznaczyć metody, narzucone przez interfejs.
#include <iostream>
using namespace std;

struct Interface {
    virtual void show() = 0;
    virtual void show2() {
        cout << "Interface" << endl;
    }
};

struct Father : public Interface {
    void show() {    // nie ma virtual i działa
        cout << "Father" << endl;
    }
};

struct Child : public Father {
    void show() {    // nie ma virtual i działa
        cout << "Child" << endl;
    }
};

int main() {
    Child c;
    c.show(); // "Child"
    return 0;
}
Nowa wersja języka, bardzo tą kwestię ułatwia. Aby mieć pewność, że przesłaniamy metodę z klasy bazowej nowy standard wprowadził słowo kluczowe override (za nazwą metody). Przesłonięcie będzie działać i dla tej klasy i dla wszystkich z niej dziedziczących. Kompilator ostrzeże nas, jeżeli popełniliśmy jakiś błąd i zamiast przesłonić stworzyliśmy coś nowego.
#include <iostream>
using namespace std;

struct Interface {
    virtual void show() = 0;
    virtual ~Interface() noexcept { }
};

struct MyClass : public Interface {
    void show() override {
        cout << "MyClass" << endl;
    }
};

int main() {
    MyClass c;
    c.show();
    return 0;
}
Choć jest możliwa inicjalizacja zmiennych klasy bazowej w klasie pochodnej, należy trzymać się zasady:
Każda klasa w momencie konstrukcji, powinna inicjalizować tylko swoje zmienne składowe.

Czasami tworzymy klasy, z których nie chcemy by ktoś inny dziedziczył, albo nie wiemy czy nadaje się ona na klasę bazową. W nowym standardzie możemy oznaczyć taką klasę słówkiem final - dziedziczenie zostanie zabronione.
struct NoDerived final {
};

struct Inher1 : NoDerived { // ERROR
};

struct Derived {
};

struct Base final : public Derived { // To jest OK
};
Przesłanianie metod (czyli tylko wirtualnych), oznaczonych jako final, zakończy się error-em.
#include <iostream>
using namespace std;

struct Interface {
    virtual void show() = 0;
};

struct Base : public Interface {
    void show() final {
        cout << "Base" << endl;
    }
};

struct Derived : public Base {
    void show() override {     // ERROR!
        cout << "Derived" << endl;
    }
};

Brak komentarzy:

Prześlij komentarz