2009-05-12 20 views
6

È possibile in Delphi utilizzare RTTI (o qualcos'altro) per verificare se una classe è dichiarata come astratta? Qualcosa di simile:Come verificare se una classe Delphi è dichiarata astratta?

TMyAbstractClass = class abstract(TObject) 
    // ... 
end; 

... 

if IsAbstract(TMyAbstractClass.ClassInfo) then 
    ShowMessage('Yeah') 
else 
    ShowMessage('Computer says no...'); 
+0

La risposta fornita a questa domanda http://stackoverflow.com/questions/791004/how-can-i-detect-if-a-delphi-class-has-a-virtual-constructor potrebbe aiutare. – RobS

risposta

0

Una rapida occhiata attraverso l'unità di TypInfo non si presenta niente di utile. Penso che la nozione di "classe astratta" sia puramente a beneficio del compilatore. Fornisce una regola per applicare - nessuna istanziazione di questa classe, solo i suoi discendenti - ma in realtà non fa nulla in fase di runtime, quindi non c'è bisogno di registrare alcun RTTI per questo.

Perché stai cercando di scoprirlo comunque, solo per curiosità?

+0

Ho una classe derivata TCollection che può contenere diversi tipi di classe (TCollectionItem) con un antenato comune. Per essere precisi è una raccolta di colonne di griglia che contiene diversi tipi di colonne. E ora voglio creare un editor di raccolte di design che permetta all'utente di aggiungere tipi di colonne registrati (usando TClassFinder) .. ma non voglio le classi abtract in questo editor. Le mie classi astratte si chiamano TCustom * quindi per ora sto filtrando usando il nome della classe. – mrMoo

+0

Il tuo problema, quindi, non riguarda il modo in cui rilevare le classi astratte. Il tuo problema è come ottenere un elenco di "tipi di colonna" validi. La soluzione facile è assicurarsi di registrare solo le classi che sono tipi di colonna validi. Non registrare le classi astratte in primo luogo. L'unico motivo per registrare una classe è che puoi cercarlo per nome e quindi istanziarlo. Non registrare classi che non sono mai state create per essere istanziate. Dovresti scoprire che il VCL non registra nemmeno le sue classi di base "personalizzate". –

+0

Sì, è vero, il problema è che registro solo le classi che sono "valide", come suggerisce tu, ma Delphi registra automaticamente anche le classi genitore, ad es. se registri TButton usando RegisterClass (TButton), Delphi registrerà anche TCustomButton, TButtonControl e così via ...Grazie comunque per il tuo post sui metodi astratti, molto interessante, ma suppongo che la risposta corretta alla mia domanda sia "No" – mrMoo

6

Non ho una versione abbastanza recente di rispondere direttamente alla tua domanda, ma di tenere presente che non davvero importa se la classeè astratta. Tutto ciò che fa è impedire al compilatore di chiamare un costruttore direttamente sulla classe. Se metti il ​​riferimento di classe in una variabile di riferimento di classe, il compilatore ti permetterà di chiamare il costruttore sulla variabile, e in fase di esecuzione avrai un'istanza della classe apparentemente non affidabile.

var 
    c: TClass; 
    o: TObject; 
begin 
    c := TMyAbstractClass; 
    o := c.Create; 
    Assert(o is TMyAbstractClass); 
end; 

Ciò che è veramente importante è se la classe ha tutti i metodi astratti. Puoi verificarlo abbastanza facilmente. Guarda nel VMT della classe. Qualsiasi slot del metodo virtuale che contenga un puntatore su System._AbstractError è un metodo astratto. La parte difficile è sapere quanti slot del metodo virtuale controllare, poiché non è registrato. Allen Bauer demonstrated how to do that in una risposta a another question, ma nei commenti Mason Wheeler sottolinea che potrebbe restituire valori più grandi di quanto dovrebbe. Menziona la funzione GetVirtualMethodCount da JCL, che dovrebbe fornire un conteggio più accurato dei metodi virtuali definiti dall'utente. Utilizzando tale funzione e GetVirtualMethod, anche dal JCL, otteniamo questa funzione:

function HasAbstractMethods(c: TClass): Boolean; 
var 
    i: Integer; 
begin 
    Result := True; 
    for i := 0 to Pred(GetVirtualMethodCount(c)) do 
    if GetVirtualMethod(c, i) = @_AbstractError then 
     exit; 
    Result := False; 
end; 

Se una classe astratta non ha metodi astratti, allora come astratta può davvero essere? Deve essere stato contrassegnato come astratto per impedire agli sviluppatori di crearne delle istanze, ma se lo si desidera, è comunque possibile crearne delle istanze, quindi contrassegnare una classe astratta è davvero più un avvertimento che qualsiasi restrizione effettiva sull'uso.

+0

Sfortunatamente, quando ho eseguito alcuni test, l'algoritmo di Allen si è rivelato non funzionante in tutti i casi. Ci guarderò un po 'e posterò una correzione in questa domanda se riuscirò a capirlo. –

+0

Apparentemente alcune altre cose possono essere messe lì davanti al nome. Invece dell'algoritmo di Allen, prova JclSysUtils.GetVirtualMethodCount, che si trova nella stessa unità JCL di GetVirtualMethod. –

+0

Infatti. La versione JCL controlla tutti gli altri puntatori nel VMT e, se uno di essi si verifica tra il primo metodo virtuale e il nome della classe, "accorcia" la finestra di ciò che considera essere l'intervallo di metodi virtuali. –

Problemi correlati