Sichtbarkeit und Vererbung

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
flitzer
Beiträge: 5
Registriert: Mi 28. Okt 2009, 14:53

Sichtbarkeit und Vererbung

Beitrag von flitzer »

Hallo liebe Leute...

Ich habe eine Frage zur Sichtbarkeit von Methoden bei der Vererbung.

Ich benutze Lazarus 0.9.28 win32 mit fpc 2.2.4

Wenn Klasse B von Klasse A abgeleitet ist, dann erbt Klasse B alle Daten von A mit den entsprechenden Sichtbarkeiten.

Wie kann man nun die Sichtbarkeit einzelner Methoden in der abgeleiteten Klasse verändern?

Mein erster Ansatz war eine Neudefinition der Methode mit anderer Sichtbarkeit und der Aufruf der inherited Methode.

Mein Minimal-Beispiel mit Sichtbarkeit von private nach public (Beispiel A):

Code: Alles auswählen

KlasseA = class
private
procedure Methode;
end;
 
procedure KlasseA.Methode;
begin
end;
 
KlasseB = class (KlasseA)
public
procedure Methode;
end;
 
procedure KlasseB.Methode;
begin
inherited Methode;
end;
Und hier der geänderte Code für die Variante von public nach private (Beispiel B):

Code: Alles auswählen

KlasseA = class
public
procedure Methode;
end;
 
KlasseB = class (KlasseA)
private
procedure Methode;
end;
Beispiel A funktioniert, sprich der Code

Code: Alles auswählen

var MyObjekt: KlasseB;
MyObjekt := KlasseB.Create;
MyObjekt.Methode;
führt zu keinem Fehler, weil Methode public ist. Das ist klar.

Der gleiche Aufruf bei Beispiel B sollte allerdings zu einem Fehler führen, weil Methode in Klasse B mit der Sichtbarkeit private überschrieben worden ist, oder?

Dem ist aber nicht so. Klasse B kennt trotzdem eine public Methode.....

Warum ist das so bzw. ist das ein Bug?

Vielen Dank für eure Antworten
Zuletzt geändert von flitzer am Mi 28. Okt 2009, 19:00, insgesamt 1-mal geändert.

monta
Lazarusforum e. V.
Beiträge: 2809
Registriert: Sa 9. Sep 2006, 18:05
OS, Lazarus, FPC: Linux (L trunk FPC trunk)
CPU-Target: 64Bit
Wohnort: Dresden
Kontaktdaten:

Re: Sichtbarkeit und Vererbung

Beitrag von monta »

Vermutlich, weil privat auch innerhalb der selben Unit sichtbar ist. Wenn du deine beiden klassen in unterschiedliche Units legst, geht das nichtmehr.

Wenn du das nicht möchtest, benutze strict privat.
Johannes

Benutzeravatar
theo
Beiträge: 11007
Registriert: Mo 11. Sep 2006, 19:01

Re: Sichtbarkeit und Vererbung

Beitrag von theo »

Afaik gibt es eine Sonderregel, wenn beide Klassen in der gleichen Unit sind (in anderen Sprachen nennt man sie dann afaik z.B. "Friends").
Sollte nicht mehr klappen wenn KlasseB in einer anderen Unit ist.

Upps, Sorry Monta, ich war wohl zu spät. ;-)
Zuletzt geändert von theo am Mi 28. Okt 2009, 17:14, insgesamt 1-mal geändert.

monta
Lazarusforum e. V.
Beiträge: 2809
Registriert: Sa 9. Sep 2006, 18:05
OS, Lazarus, FPC: Linux (L trunk FPC trunk)
CPU-Target: 64Bit
Wohnort: Dresden
Kontaktdaten:

Re: Sichtbarkeit und Vererbung

Beitrag von monta »

ich war schneller ;)
Johannes

Benutzeravatar
theo
Beiträge: 11007
Registriert: Mo 11. Sep 2006, 19:01

Re: Sichtbarkeit und Vererbung

Beitrag von theo »

Schon wieder (siehe Edit)

flitzer
Beiträge: 5
Registriert: Mi 28. Okt 2009, 14:53

Re: Sichtbarkeit und Vererbung

Beitrag von flitzer »

Danke erstmal für eure Antworten...

Ich hänge mal eine zip-Datei an mit einem Beispielprogramm.

Das Programm lagert die 2 Klassen in 2 Units aus.

KlasseB erbt KlasseA, welche eine public procedure CalcBerechnungen enthält und überschreibt diese mit einer eigenen private procedure CalcBerechnungen = inherited CalcBerechnungen...

Ein Objekt vom Typ TKlasseB besitzt dann aber trotzdem die geerbte öffentliche Methode CalcBerechnungen?

Kann es sein, daß CalcBerechnungen nicht überschrieben, sondern überladen wird, obwohl ich nicht das Schlüsselwort overload verwende?

Bin gespannt, was ihr sagt

P.S. ich probier nochmal ein bisschen mit strict privat
Dateianhänge
Sichtbarkeit_Vererbung_01.zip
Beispiel-Source
(347.38 KiB) 103-mal heruntergeladen

Hitman
Beiträge: 512
Registriert: Mo 25. Aug 2008, 18:17
OS, Lazarus, FPC: ArchLinux x86, WinVista x86-64, Lazarus 0.9.29, FPC 2.4.1
CPU-Target: x86
Wohnort: Chemnitz

Re: Sichtbarkeit und Vererbung

Beitrag von Hitman »

Wie du auch der Dokumentation entnehmen kannst, kann die Sichtbarkeit nicht degradiert werden - nur umgekehrt. Mich wundert allerdings, dass der Compiler an der Stelle nicht gleich einen Fehler wirft, aber anscheinend ist er da relativ kulant :D

Benutzeravatar
theo
Beiträge: 11007
Registriert: Mo 11. Sep 2006, 19:01

Re: Sichtbarkeit und Vererbung

Beitrag von theo »

Ich habe kürzlich einen Bug in diesem Bereich eingetragen. Könnte also in trunk behoben sein.
http://bugs.freepascal.org/view.php?id=14650" onclick="window.open(this.href);return false;

flitzer
Beiträge: 5
Registriert: Mi 28. Okt 2009, 14:53

Re: Sichtbarkeit und Vererbung

Beitrag von flitzer »

Hitman hat geschrieben:Wie du auch der Dokumentation entnehmen kannst, kann die Sichtbarkeit nicht degradiert werden - nur umgekehrt. Mich wundert allerdings, dass der Compiler an der Stelle nicht gleich einen Fehler wirft, aber anscheinend ist er da relativ kulant :D
Hallo und danke für deine Antwort...

Wo genau ist das dokumentiert?

Im Programmer's Guide und Reference Guide hab ich unter visibility bzw. inheritance nichts gefunden...

Hitman
Beiträge: 512
Registriert: Mo 25. Aug 2008, 18:17
OS, Lazarus, FPC: ArchLinux x86, WinVista x86-64, Lazarus 0.9.29, FPC 2.4.1
CPU-Target: x86
Wohnort: Chemnitz

Re: Sichtbarkeit und Vererbung

Beitrag von Hitman »

Ich kenn das noch aus meiner Delphi Zeit. Da die Docs aber nicht öffentlich sind, kann ich grad höchstens hier drauf verweisen:
http://www.mail-archive.com/fpc-pascal@ ... 08001.html" onclick="window.open(this.href);return false;

Hier jedoch noch das Zitat aus der Delphi Hilfe:

Code: Alles auswählen

Sie können die Sichtbarkeit eines Elements in einer untergeordneten Klasse durch Redeklarieren erhöhen, jedoch nicht verringern. So kann beispielsweise eine protected-Eigenschaft in einer abgeleiteten Klasse als public deklariert werden, nicht aber als private. Außerdem können published-Elemente nicht zu public-Elementen gemacht werden.

flitzer
Beiträge: 5
Registriert: Mi 28. Okt 2009, 14:53

Re: Sichtbarkeit und Vererbung

Beitrag von flitzer »

Ich denke, die Variante von Hitman klingt am plausibelsten...

Aus irgendwelchen Gründen ist es nicht vorgesehen bzw. nicht möglich, die Sichtbarkeit zu verringern. Ich vermute einfach mal, daß es (1.) einen plausiblen Grund geben wird, oder aber (2.) irgendwelche objektorientierten Spitzfindigkeiten dagegen sprechen oder aber (3.) es doch eine Lösung gibt.....

Somit lade ich nochmal alle ein zu einem Brainstorming zum Thema:

Kann man die Sichtbarkeit von Methoden in abgeleiteten Klassen verringern? Und wenn ja, wie?

Grüße
Zuletzt geändert von flitzer am Do 29. Okt 2009, 10:30, insgesamt 1-mal geändert.

RSE
Beiträge: 462
Registriert: Mi 30. Jul 2008, 13:11
OS, Lazarus, FPC: WinXP SP3 (L 0.9.28.2 FPC 2.2.4)
CPU-Target: 32Bit
Kontaktdaten:

Re: Sichtbarkeit und Vererbung

Beitrag von RSE »

flitzer hat geschrieben:Kann man die Sichtbarkeit von Methoden in abgeleiteten Klassen erhöhen? Und wenn ja, wie?
Ich nehme an du meintest verringern ;-)

Mein sehr unqualifizierter Senf dazu lautet folgendermaßen:
Es gibt doch irgendwo eine Tabelle mit den ganzen Einsprungadressen für die Prozeduren. Diese wird "entlang der Klassenhierarchie" einmalig im Objekt aufgebaut. Ich nehme an, es gibt eine für jede Sichtbarkeit, die dann in der entsprechenden Sichtbarkeit liegt (die mit den privaten Einsprungadressen ist auch nur privat referenziert/erreichbar). Wenn nun eine Prozeduradresse einmal in der public-Tabelle steht, steht sie eben drin. Es ist sicherlich nicht ohne, in so einer Tabelle dann in einer abgeleiteten Klasse nochmal drin rumzupfuschen und einen Wert zu löschen bzw. den Eintrag irgendwie unbrauchbar zu machen, weil er ja dann auch für den Code nicht mehr existiert, für den die methode noch public ist.... Ich denke ein Beispiel tut Not.

Beispiel (Klasse B ist von A abgeleitet, Klasse C von B usw.):

Klasse A definiert Methode MA als public, erzeugt somit einen Eintrag in der public-Tabelle
Klasse B nutzt Methode MA (ruft also B.MA auf, greift damit auf die public-Tabelle zu und gelangt so auf den Code von A.MA)
Klasse C macht die Methode MA private, macht also den Eintrag in der public-Tabelle unbrauchbar *peng* Der Aufruf B.MA funktioniert nicht mehr, weil die Tabelle eben nur einmal im Objekt vorkommt.
Seit er seinen neuen Computer hat, löst er alle Probleme, die er vorher nicht hatte!

flitzer
Beiträge: 5
Registriert: Mi 28. Okt 2009, 14:53

Re: Sichtbarkeit und Vererbung

Beitrag von flitzer »

@RSE

Ich meinte natürlich verringern, klar... Es war schon spät und ich müde... sorry...

Gibt es keine Chance eine Methode wieder zu verbergen, wenn sie einmal public definiert ist?

Seltsam...

Hitman
Beiträge: 512
Registriert: Mo 25. Aug 2008, 18:17
OS, Lazarus, FPC: ArchLinux x86, WinVista x86-64, Lazarus 0.9.29, FPC 2.4.1
CPU-Target: x86
Wohnort: Chemnitz

Re: Sichtbarkeit und Vererbung

Beitrag von Hitman »

In der von mir verlinkten Diskussion (siehe oben) sind zumindest einige Workarounds genannt. Der günstigste wohl: die zu "verdeckende" Methode überschreiben und statt inherited aufzurufen eine Exception werfen. Somit kann man zumindest den Aufruf bestrafen.

Benutzeravatar
theo
Beiträge: 11007
Registriert: Mo 11. Sep 2006, 19:01

Re: Sichtbarkeit und Vererbung

Beitrag von theo »

flitzer hat geschrieben: Gibt es keine Chance eine Methode wieder zu verbergen, wenn sie einmal public definiert ist?
Afaik nein. Ist ja auch irgendwie logisch. Was würden sonst die Sichtbarkeiten (private, protected, public..) für einen Sinn machen, wenn man sie in der abgeleiteten Klasse wieder beliebig verändern könnte? Mindestens protected wäre dann ja überflüssig.

Mit dem "private" Verhalten innerhalb der Unit bin aber eigentlich nicht glücklich.
Ich fände es besser, wenn dies standardmässig immer "strict" wäre.
Man könnte dann über eine explizite Freigabe innerhalb der Unit diskutieren, z.B. "extern private" oder sowas.
Das verleitet sonst zu "autistischem Code", wo eine vernünftige Vererbbarkeit nicht berücksichtigt wird, weil es in der eigenen Unit ja klappt.
Beispiele dafür gibt es im Delphi Code genug.

Antworten