2012-06-18 11 views
7

Kiedy definiujesz konstruktor klasy w klasie bazowej (tj. Ustawiasz pewną statyczną zmienną klasy), czy możliwe jest przesłonięcie tego konstruktora klasy w klasie pochodnej i wywołanie konstruktora z jego hierarchicznego elementu nadrzędnego z odziedziczonym?Czy można zastąpić konstruktor klasy i korzystać z dziedziczenia?

Przykład:

TBaseclass = class(TObject) 
public 
    class constructor ClassCreate; virtual; 
end; 

TOtherClass = class(TBaseClass) 
public 
    class constructor ClassCreate; override; 
end; 

**implementation** 

class constructor TBaseClass.ClassCreate; 
begin 
    //do some baseclass stuff 
end; 

class constructor TotherClass.ClassCreate; 
begin 
    inherited; 
    //do some other stuff 
end; 

Odpowiedz

16

Nie ma powodu, dla class constructors być wirtualny, ponieważ nie można powoływać polimorficznie. Nie możesz ich wywołać bezpośrednio; kompilator automatycznie woła do nich wywołania na podstawie klas używanych w programie. Metody wirtualne są przeznaczone do polimorfizmu czasu wykonywania, ale ponieważ kompilator dokładnie wie, które konstruktory klas wywołuje w czasie kompilacji, nie ma potrzeby dynamicznego wysyłania do konstruktorów klas lub destruktorów.

Metody wirtualne nie są jednak wymagane do dziedziczenia, więc nie powinno być problemu z używaniem inherited w konstruktorze klasy lub destruktorze klas. Jednakże, jak wskazuje David's answer, kompilator ignoruje wywołania do inherited, ponieważ generalnie nierozsądne jest zainicjowanie klasy wiele razy, co robilibyśmy, gdyby naprawdę udało się wywołać dziedziczony konstruktor klasy. Jeśli jest coś, co musisz zrobić dwa razy, musisz znaleźć inny sposób, aby to się stało.

+1

+1 dla "kompilator automatycznie wywołuje do niego połączenia na podstawie klas używanych w programie". Konstruktorzy klasy sprawiają, że inteligentne linkowanie jest bardziej wydajne. (ponieważ inicjowanie powiązanych zmiennych jest uzależnione od użycia klasy) –

+0

Nie, @Marjan. To nie było niewytłumaczalne głosowanie. Było to głosowanie przez kogoś, kto pomylił "konstruktor klasy" z "konstruktorem", a następnie wziął pod uwagę twierdzenie mojego i Davida, że ​​nie mogą być wirtualni i nie mieliby najmniejszego pożytku, gdyby mogli. Ci, którzy mają dość reputacji, mogą zobaczyć odpowiedź "odpierającą", która została później usunięta, ponieważ wskazałem na nieporozumienie w terminologii. Komentarze wyjaśniające głosowanie zostały już usunięte. –

+0

Szczerze mówiąc, faktyczny szczegół odpowiedzi jest zbyt obszerny, po prostu dlatego, że nigdy nie musiałem robić takich rzeczy. Ale Rob, +1, naprawdę jesteś mistrzem wyjaśnienia. –

9

Na początek, ponieważ konstruktorzy klasa nie może być wirtualny (nie ma sensu dla nich być wirtualny), trzeba usunąć virtual i override słowo aby dokonać kompilacji kodu.

Konstruktory klas są zwykle używane do inicjowania zmiennych klas. Odwoły klasowe zwykle wymagają inicjalizacji tylko raz i tylko raz. Jeśli możesz zadzwonić pod numer inherited w sposób sugerowany w pytaniu, to TBaseClass.ClassCreate będzie wywoływany wiele razy, podczas gdy w rzeczywistości musi być wywołany dokładnie jeden raz.

Podczas gdy można napisać inherited w konstruktorze klasy, a kod się skompiluje, kompilator po prostu je zignoruje.

program ClassConstructors; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

var 
    Count: Integer; 

type 
    TBaseclass = class 
    public 
    class constructor ClassCreate; 
    end; 

    TOtherClass = class(TBaseClass) 
    public 
    class constructor ClassCreate; 
    end; 

class constructor TBaseClass.ClassCreate; 
begin 
    inc(Count); 
end; 

class constructor TotherClass.ClassCreate; 
begin 
    inherited; 
end; 

begin 
    TBaseClass.Create.Free; 
    TOtherClass.Create.Free; 
    Writeln(Count);//outputs 1 
    Readln; 
end. 

Należy zauważyć, że oba konstruktory klas działają.

+0

Dziękuję za komentarze! Ale czy wywołania 'dziedziczone' zawsze są ignorowane przez kompilator? Pomyślałem, że istnieją "odziedziczone poglądy Create (AOwner)". Czy są zduplikowane połączenia? Czy możesz pomóc w komentarzach? – SOUser

+1

@XichenLi 'odziedziczony' zostaje zignorowany tylko wtedy, gdy nie ma sensu. Na przykład konstruktorzy klas. Lub w metodach, które zastępują abstrakcyjne metody. –

+2

@DavidHeffernan: przesłonięte metody abstrakcyjne wywołują dziedziczenie i generują wyjątek EAbstractError, jeśli/po "odziedziczeniu SomeMethodName;" zamiast po prostu 'odziedziczonym;' –

Powiązane problemy