2009-05-12 10 views
6

Czy w Delphi można używać RTTI (lub czegoś innego) do sprawdzenia, czy dana klasa jest deklarowana jako abstrakcyjna? Coś jak:Jak sprawdzić, czy klasa Delphi jest deklarowana jako abstrakcyjna?

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

... 

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

Odpowiedź udzielona na to pytanie http://stackoverflow.com/questions/791004/how-can-i-detect-if-a-delphi-class-has-a-virtual-constructor może pomóc. – RobS

Odpowiedz

0

Szybkie spojrzenie przez jednostkę TypInfo nie włącza się niczego przydatne. Myślę, że pojęcie "klasy abstrakcyjnej" jest wyłącznie z korzyścią dla kompilatora. Daje to regułę do wymuszania - bez tworzenia instancji tej klasy, tylko jej potomków - ale tak naprawdę nie robi nic w czasie wykonywania, więc nie ma potrzeby rejestrowania dla niej żadnego RTTI.

Dlaczego próbujesz to odkryć, po prostu z ciekawości?

+0

Mam klasy pochodne TCollection, które mogą zawierać różne typy klas (TCollectionItem) ze wspólnym przodkiem. Aby być specyficznym, jest to kolekcja kolumn siatki, która zawiera różne typy kolumn. A teraz chcę utworzyć edytor kolekcji designtime, który umożliwia użytkownikowi dodawanie zarejestrowanych typów kolumn (przy użyciu TClassFinder) .. ale nie chcę klas abtract w tym edytorze. Moje abstrakcyjne klasy nazywają się TCustom *, więc na razie filtruję używając nazwy klasy. – mrMoo

+0

Twój problem nie dotyczy więc wykrywania klas abstrakcyjnych. Twój problem polega na uzyskaniu listy prawidłowych "typów kolumn". Łatwym rozwiązaniem jest upewnienie się, że rejestrujesz tylko klasy, które są prawidłowymi typami kolumn. Nie rejestruj klas abstrakcyjnych w pierwszej kolejności. Jedynym powodem zarejestrowania klasy jest wyszukanie jej według nazwy, a następnie utworzenie jej. Nie rejestruj klas, które nigdy nie mają być tworzone. Powinieneś odkryć, że VCL również nie rejestruje własnych "niestandardowych" klas bazowych. –

+0

Tak, to prawda, problem polega na tym, że rejestruję tylko te klasy, które są "prawidłowe", jak sugerujesz, ale Delphi automatycznie rejestruje również klasy nadrzędne, np. jeśli zarejestrujesz TButton używając RegisterClass (TButton), Delphi zarejestruje również TCustomButton, TButtonControl i tak dalej ...Mimo to dzięki za twój post o metodach abstrakcyjnych, bardzo interesujące, ale myślę, że poprawna odpowiedź na moje pytanie brzmi "Nie" – mrMoo

6

nie mam wersję wystarczająco wcześnie, aby odpowiedzieć na to pytanie bezpośrednio, ale należy pamiętać, że nie naprawdę sprawę, czy klasajest abstrakcyjny. Wszystko to sprawia, że ​​kompilator powstrzymuje Cię przed wywołaniem konstruktora bezpośrednio na klasie. Jeśli odwołanie do klasy zostanie umieszczone w zmiennej odwołującej się do klasy, kompilator umożliwi wywołanie konstruktora zmiennej, aw czasie wykonywania będziesz miał instancję rzekomo nieusuwalnej klasy.

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

Co jest naprawdę ważne jest czy klasa ma jakieś metody abstrakcyjne. Możesz to łatwo sprawdzić. Zajrzyj do VMT klasy. Każde gniazdo metody wirtualnej zawierające wskaźnik do System._AbstractError jest metodą abstrakcyjną. Najtrudniejsze jest poznanie, ile automatów wirtualnych należy sprawdzić, ponieważ nie jest to rejestrowane. Allen Bauer demonstrated how to do that w odpowiedzi na another question, ale w komentarzach Mason Wheeler wskazuje, że może zwracać większe wartości niż powinien. Wymienia on funkcję GetVirtualMethodCount z JCL, która powinna zapewniać dokładniejszą liczbę wirtualnych metod zdefiniowanych przez użytkownika. Korzystanie z tej funkcji i GetVirtualMethod, również z JCL, mamy tę funkcję:

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; 

Jeśli klasa abstrakcyjna nie ma metody abstrakcyjne, to jak streszczenie może być naprawdę? Musiało być oznaczone jako abstrakcyjne, aby uniemożliwić programistom tworzenie jego wystąpień, ale jeśli naprawdę tego chcesz, możesz mimo to utworzyć jego wystąpienia, więc zaznaczenie klasy abstrakcyjnej jest bardziej ostrzeżeniem niż faktycznym ograniczeniem użycia.

+0

Niestety, gdy przeprowadziłem testy, algorytm Allena okazał się nieskuteczny we wszystkich przypadkach. Przyjrzę się temu nieco i dodam korektę w tym pytaniu, jeśli uda mi się to ustalić. –

+0

Podobno inne rzeczy mogą zostać umieszczone przed nazwą. Zamiast algorytmu Allena wypróbuj JclSysUtils.GetVirtualMethodCount, który jest dogodnie zlokalizowany w tej samej jednostce JCL co GetVirtualMethod. –

+0

Rzeczywiście. Wersja JCL sprawdza wszystkie inne wskaźniki w VMT, a jeśli którykolwiek z nich występuje między pierwszą metodą wirtualną a nazwą klasy, "skraca" okno tego, co uważa za zakres metod wirtualnych. –