Klasa NIE dziedzicząca po TObject

0

Czy jest możliwość napisania własnej klasy od podstaw która nie dziedziczy po TObject? I jeśli jest możliwość to jakie są tego zalety oraz wady? A jeśli nie ma takiej możliwości to czemu?

Wiem, że pytanie może się wydawać głupie ale w sumie kodzę sobie i kodzę i korzystam z dobrodziejstw programowania obiektowego ale nigdy nie zastanawiałem się nad sensem klasy TObject po której domyślnie dziedziczą wszystkie inne klasy. I chce poznać dokładne działanie konstruktora i destruktora. Bo niby wiem jak to działa i rozumiem zasadę działania ale dochodzi pytanie dlaczego to tak działa?

1

Możesz napisać:

  MyClass = class
  ...
  end;

ale to i tak dziedziczy po TObject

Sens jest prosty TObject ma wirtualny destruktor.

0

Znaczy nie da się napisać klasy nie dziedziczącej po TObject. I teraz zrozumiałem już dokładnie o co chodzi, trybiki w mózgu się przekręciły :)

0

Znaczy nie da się napisać klasy nie dziedziczącej po TObject.

Cóż, teoretycznie można by zmusić do tego kompilator zmieniając źródło, tylko po co? TObject jest klasą bazową wszystkich klas. Gdyby nie TObject, to nie wiem jakbym w parametrze funkcji napisał 'dowolna klasa'. Bo może to być klasa tego samego typu albo bazowa dla tej którą podamy. Jeżeli podamy TObject to każda będzie pasować (łącznie z samym TObject).

Sens jest prosty TObject ma wirtualny destruktor.

No ale właściwie co z tego. Możesz napisać kompilator aby generował wirtualny konstruktor zawsze. Natomiast ciężko wtedy byłoby zrobić sytuację którą opisałem wyżej. Już nie mówiąc o tym że TObject ma inne ciekawe pola jak np. takie które zwracają nazwę klasy itp.

nigdy nie zastanawiałem się nad sensem klasy TObject po której domyślnie dziedziczą wszystkie inne klasy

No to mam nadzieję że ci wyjaśniliśmy. Teoretycznie można by to zmienić, ale to skomplikowałoby wiele rzeczy (jak nazwać systemowy destruktor jak nie TObject.Destroy, jak nazwać systemowy konstruktor jak nie TObject.Create, jak zapewnić możliwość dania dowolnej klasy jako parametru procedury).

A tak pół żartem pół serio: http://ideone.com/n33lAE

0

@kwq84i2 - pod FPC podany przez Ciebie kod zwraca False, ale tylko w przypadku, gdy obiekt nie został zainicjowany (utworzony); Jeśli natomiast obiekt utworzymy:

program Project1;

{$mode objfpc}{$H+}

uses
  SysUtils;

type
  TFoo = class
  end;

var
  Foo: TFoo;
begin
  Foo := TFoo.Create();  
  Write(BoolToStr(Foo is TObject, True));  
  Foo.Free();
  
  ReadLn;
end.

i po jego utworzeniu sprawdzimy - na ekranie zostanie wyświetlony napis True (pod Lazarusem 1.0.8); Inaczej sprawa ma się w Delphi 7 - bez względu na to, czy obiekt jest utworzony w pamięci czy nie:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TFoo = class
  end;

var
  Foo: TFoo;
begin
  Write(BoolToStr(Foo is TObject, True));
  ReadLn;
end.

warunek Foo is TObject zawsze będzie prawdziwy;

0
Azarien napisał(a)

po co wam to BoolToStr, skoro można bezpośrednio writelnować boola? :-)

Racja, przyzwyczajenie gdy się chce coś do stringa wrzucić.

Patryk27 napisał(a)

Zapewne Delphi rozwija operator is w trakcie kompilacji (jeżeli możliwe), a FPC dopiero podczas działania programu.

W sumie to D7 racji nie ma, bo zakłada że obiekt jest stworzony, natomiast FPC poprawnie stwierdza, że skoro nie ma utworzonej klasy to nie należy ona do żadnego typu klasy. Być może FPC po prostu widzi że zmienna jest niezainicjalizowana i nie używa skracania. D7 nie robi tego tam, gdzie to możliwe, tylko raczej robi to nadgorliwie.

Patryk27 napisał(a)

Btw, {$APPTYPE CONSOLE} nie jest we FPC potrzebne, bo afair jest to i tak domyślny tryb.

Tylko że to najprawdopodobniej kod D7. W FPC nie trzeba używać żadnego przełącznika kompilatora w ten sposób, gdyż wszystkie opcje są dostępne z poziomu parametrów kompilacji.

furious programming napisał(a):

@kwq84i2 - pod FPC podany przez Ciebie kod zwraca False, ale tylko w przypadku, gdy obiekt nie został zainicjowany (utworzony); Jeśli natomiast obiekt utworzymy:

Doskonale o tym wiem, dlatego półżartem półserio. Natomiast nota na temat D7 jest ciekawa.

0
kwq84i2 napisał(a):

W sumie to D7 racji nie ma, bo zakłada że obiekt jest stworzony, natomiast FPC poprawnie stwierdza, że skoro nie ma utworzonej klasy to nie należy ona do żadnego typu klasy. Być może FPC po prostu widzi że zmienna jest niezainicjalizowana i nie używa skracania. D7 nie robi tego tam, gdzie to możliwe, tylko raczej robi to nadgorliwie.

Zależy jak komu wygodnie to interpretować w końcu zmienna jest określonego typu. Dlaczego nie możesz sobie zmienić typu zmiennej dynamicznie? A w FPC wygląda na to że możesz bo coś co nie jest TObject nagle jest TObject. Po prostu dziwna sprawa że oba kompilatory różnie to interpretują, natomiast który to robi prawidłowo to sprawa dyskusyjna.

0

Jednoznacznie wole działanie FPC, bo mogę w ten sposób stwierdzić czy obiekt jest zainicjalizowany.

0

Nie czytacie uważnie - pierwszy kod był kompilowany pod Lazarusem (1.0.8), a ten drugi pod Delphi 7 ;)

Wybacz mi, ale kogo masz na myśli? Z mojego postu chyba jasno wynika że wiem o co chodzi. Tym bardziej nie rozumiem dlaczego piszesz komentarz do mojego postu.

Zależy jak komu wygodnie to interpretować w końcu zmienna jest określonego typu.

Hm...

a:TStrings;
begin
  a:=TStringList.Create;

Jakiego typu jest tutaj zmienna?

Dlaczego nie możesz sobie zmienić typu zmiennej dynamicznie?

Bo to Pascal.

A w FPC wygląda na to że możesz bo coś co nie jest TObject nagle jest TObject.

hm, raczej: coś co nie istnieje, nie jest TObject. Typ zmiennej wciąż jest TObject, tylko że to jest wskaźnik na właściwą klasę. Skoro wskaźnik jest 'nil' to ja taki pewien nie jestem czy jest on typu TObject. Typu nie określa zmienna do której to jest przypisane.

Po prostu dziwna sprawa że oba kompilatory różnie to interpretują, natomiast który to robi prawidłowo to sprawa dyskusyjna.

Cóż, zależy czy dla ciebie nil is TObject :)

Jednoznacznie wole działanie FPC, bo mogę w ten sposób stwierdzić czy obiekt jest zainicjalizowany.

Do tego jest assigned ale jednak może to być traktowane jako 'awaryjne' działanie.

No tak to jet plus, tyle że is w zasadzie chyba nie zostało stworzone do sprawdzania czy istnieje czy nie tylko czym jest (jakiego jest typu) "The is operator, which performs dynamic type checking, is used to verify the actual runtime class of an object.". Takie coś to powinno się sprawdzać inną metodą jak Assigned tyle że Assigned tylko wtedy działa poprawnie gdy przy zwalnianiu przypiszesz nil.

Dlatego się używa FreeAndNil.

1 użytkowników online, w tym zalogowanych: 0, gości: 1