Dziedzieczenie z TObject

0

Cześć Wszystkim,
zaczynam uczyć się Delphi i pojawiły się u mnie pytania odnośnie tworzenia własnego obiektu. Próbowałem utworzyć dwa konstruktory

constructor Create; overload;
constructor Create(name: String); overload;

I tutaj pojawia mi się błąd "Unsatisfied forward or external declaration: myObject.Create"
Co ciekawe nie mogę dodać override

constructor Create; overload; override;

Krzyczy: "Cannot override a non-virtual method". Oddzielnie mogę bez problemu wywołać oba konstruktory.
Proszę też o odpowiedź na dwa pytania:

  1. Rozumiem, że zapis
myObject = class

jest równoznaczny z

myObject = (TObject)
  1. Inherited oznacza wywołanie z klasy rodzica metody, o podanej nazwie, czy nazwie konstruktora, którego jest wywoływana. Przykładowo:
constructor Create(name: String);
begin
   inherited Create;
end;

oznacza wywołanie z rodzica metody Create, czy Create(name: String)?

  1. Czy dziedzicząc z TObject, TComponent lub własnych klas trzeba stosować inherited w konstruktorach?
1
  1. Override można robić tylko na wirtualnych metodach.
  2. Każda klasa domyślnie dziedziczy po TObject.
  3. Nie, inherited nie jest wymagane, wszystko zależy od tego co chcesz osiągnąć (dlaczego chcesz go wywołać?).
  4. Ogólnie, zamiast inherited Create, samo inherited też wystarczy jeśli nie ma tam argumentów, wtedy konstruktor tej klasy wykona instrukcje dziedziczonego konstruktora (o ile istnieją).

Co konkretnie chcesz osiągnąć?

Edit: jeśli wolno spytać - po co uczysz się Delphi?

4

W delphi klasa składa się z dwóch części (zazwyczaj, ale o tym zaraz) - deklaracji i implementacji. W tym przypadku "Unsatisfied forward or external declaration: myObject.Create" brakuje Ci implementacji i nie ma to nic wspólnego z klasą bazową czy dziedziczeniem. Implementacji może nie być jeśli nie ma co implementować :) - jeśli klasa nie ma żadnej metody to nic nie implementuje.

Jak już wspomniał @TomekCph nie każdą metodę można nadpisać (override) - aby można było daną metodę nadpisać musi ona być zadeklarowana w klasie bazowej jako wirtualna (virtual) albo dynamiczna (dynamic) oraz musi mieć identyczną ilość oraz typ parametrów.

Domyślnie każda klasa dziedziczy z TObject (bezpośrednio lub pośrednio) i zapis TMyClass = class jest równoważny z TMyClass = class(TObject)

Można przyjąć, że inherited wskazuje najbliższego przodka implementującego daną metodę i wywołuje tą metodę. inherited ma dwie postacie - może wystąpić samo i wtedy "szuka" metody z taką samą nazwą, liczbą i typem parametrów w jakiej występuje albo można po niej podać wprost nazwę metody i parametry do wywołania.

Zazwyczaj logika dziedziczenia wymaga wołania inherited z każdej dziedziczącej klasy. Są przypadki, gdzie nie woła się inherited ale wtedy musisz dokładnie znać całą ścieżkę dziedziczenia i wiedzieć co robisz. Brak zawołania inherited może prowadzić do różnych skutków ubocznych - przy braku zawołania z konstruktora istniej duża szansa, że czegoś będzie brakować (np. będziesz miał niezainicjowane zmienne z klas bazowych); przy braku wołania z destruktora najczęstszym wynikiem są wycieki pamięci (niezwolnione nieużywane zmienne); brak w "regularnych" metodach najczęściej prowadzi do działania niezgodnie z zakładaną logiką i jest trudne do namierzenia.

Jak zwykle dokumentacja pomaga zrozumieć podstawy http://docwiki.embarcadero.com/RADStudio/Rio/en/Methods_(Delphi)

1
PanAndrzej napisał(a):

Przykładowo:

constructor Create(name: String);
begin
   inherited Create;
end;

oznacza wywołanie z rodzica metody Create, czy Create(name: String)?

Pierwszego, czyli bezparametrowego, z bazowej klasy.

PanAndrzej napisał(a):
  1. Czy dziedzicząc z TObject, TComponent lub własnych klas trzeba stosować inherited w konstruktorach?

W przypadku dziedziczenia z TObject nie trzeba, bo konstruktor tej klasy ma pustą definicję. Ale dodanie inherited w tym przypadku niczego nie zepsuje – po prostu nic nie zostanie wykonane. W przypadku dziedziczenia z innych klas trzeba, jeśli zależy Ci na wykonaniu logiki z bazowego konstruktora – czyli w praktyce także. ;)

0

@abrakadaber: racja, zapomniałem, jeszcze dynamiczne mogą być nadpisywane :)

EDIT: ogólnie Twój post to bardzo wyczerpująca odpowiedź!

0

Bardzo się cieszę i dziękuję, że tak chętnie opowiadacie. Język Delphi bardzo mi się spodobał, ze względu na szybkość, prostotę działania, łatwość obsługi. Jestem pod wrażeniem tego, że przez lata miał rozwiązania, które dopiero teraz świat docenia i implementuję. A ogólnie to programuję dla siebie, dla przyjemności.

Z implementacją racja, deklarowałem dwa konstruktory, a komentowałem jedną z deklaracji. Ja docelowo chciałem stworzyć po prostu dwa konstruktory, każdy z innymi wartościami. A sprawa inherited to oddzielne pytanie - stosować je właśnie chciałem, żeby nie pominąć kodu z konstruktora rodzica. Ja po prostu dla nieznanych mi klas konstruktorów będę stosował inherited, a przy własnych będę mógł czasami pomijać.

Na tę chwile to chyba wszystko. Jeszcze raz dziękuję i życzę zdrowia :)

0
PanAndrzej napisał(a):

Jestem pod wrażeniem tego, że przez lata miał rozwiązania, które dopiero teraz świat docenia i implementuję.

Czyli które? Chyba Cię poniosło. ;)

Ja po prostu dla nieznanych mi klas konstruktorów będę stosował inherited, a przy własnych będę mógł czasami pomijać.

Jeśli nie wiesz co wykonuje konstruktor z bazowej klasy to wołaj inherited. Zresztą, jeszcze się nie spotkałem z przypadkiem, kiedy to się go nie woła w konstruktorze, celowo nie wykonując kodu bazowego (nie licząc dziedziczenia bezpośrednio z TObject).

Natomiast własne klasy projektuj w taki sposób, aby też zawsze wołać bazowy konstruktor. Sprawa wygląda nieco inaczej, jeśli chodzi o metody wirtualne, bo można celowo nie wołać inherited (lub robić to w innym miejscu niż na początku bloku kodu metody), ale tutaj musi być konkretny powód, czyli znajomość logiki klas bazowych.

0
furious programming napisał(a):
PanAndrzej napisał(a):

Jestem pod wrażeniem tego, że przez lata miał rozwiązania, które dopiero teraz świat docenia i implementuję.

Czyli które? Chyba Cię poniosło. ;)

Jednak nie do końca poniosło.
A które?
Np. przyrostowy kompilator - porównaj sobie czas kompilacji sporego projektu w C++ i Delphi.
No i RAD sam z siebie; co prawda ta technika najlepsze lata ma za sobą i jestem jej zdecydowanie przeciwny, zwłaszcza kiedy jest nadużywana wszędzie, ale... ;-)
Najpierw jest Delphi, a potem niby co?

No i ten one-code-base Delphi rozwija konsekwentnie od lat. Można narzekać, ze nie tak, że źle... Ale jest rozwijany, działa i jest coraz lepiej.
Nawet na tyle lepiej, że i DevEx zapowiedział że dostarczy coś od siebie dla FMX :)

Problemem Delphi nie jest nadążanie za sugar syntactic tylko zgodność ze standardami, że tak powiem, przemysłowymi.
Coś co w innych językach jest dostępne ot tak i używam za friko (np. uczenie maszynowe albo integracja z ODATA czy SAP ERP albo całkowicie banalne WebSocket czy MQTT; tylko proszę mi nie pisać, że jest np. na GitHubie bo nie zdzierżę; jest, ale pisane na kolanie bez testów i de-facto wspiera tylko wycinek specyfikacji jak np. MQTT bez QoS 1 i 2), tu muszę albo się sporo namęczyć albo kupić coś za ciężkie USD.

1
wloochacz napisał(a):

Np. przyrostowy kompilator - porównaj sobie czas kompilacji sporego projektu w C++ i Delphi.

Znajdę gdzieś taki sam duży projekt napisany w dwóch językach, żeby taki test miał realną wartość? ;)

No i RAD sam z siebie; […]

Tyle że RAD w innych technologiach nie istnieje od roku, a od dawna. Wiadomo, że nie od tak dawna jak w Delphi, ale zdecydowanie nie jest to nowość. Ten argument już nie jest tak mocny jak choćby 10 lat temu.

0
furious programming napisał(a):
wloochacz napisał(a):

Np. przyrostowy kompilator - porównaj sobie czas kompilacji sporego projektu w C++ i Delphi.

Znajdę gdzieś taki sam duży projekt napisany w dwóch językach, żeby taki test miał realną wartość? ;)

No i RAD sam z siebie; […]

Tyle że RAD w innych technologiach nie istnieje od roku, a od dawna.

Że co?
A WinForms czy inny QT to pies?
Niby nieużywany? Zdziwiłbyś się.
A Lazarus? :D

A z nowych rozwiązań to np. RadZEN.

O nim się teraz nie mówi tak dużo jak o innych cudach, ale że nie istnieje to przesada.

Wiadomo, że nie od tak dawna jak w Delphi, ale zdecydowanie nie jest to nowość.

Nie twierdzę, że to nowość.
Twierdzę, ze to jednak i mimo wszystko wartość dodana.

Ten argument już nie jest tak mocny jak choćby 10 lat temu.

Niby nie, ale na poletku aplikacji line-of-business jednak dalej to ważki argument.

1
wloochacz napisał(a):

Że co?
A WinForms czy inny QT to pies?
Niby nieużywany? Zdziwiłbyś się.
A Lazarus? :D

Ekhm… przeczytaj jeszcze raz to zdanie. Właśnie o to w nim chodzi, że inne RAD-y i RAD-opodobne twory istnieją od dawna, a nie od roku, więc pisanie, że dopiero teraz świat docenia technologie opracowane przez Borland jest spóźnione… o całe lata. ;)

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