Warum bricht 'protected' die Kapselung?
-
Guten Abend Forum,
ich habe jetzt schon öfters gelesen, dass der Zugriffsmodifizierer 'protected' die Kapselung bricht.
Aber warum ist das so?
Ich habe schon mehrere Diskussionen dazu gelesen, aber ich bin immer noch nicht dahintergekommen, was denn der tatsächliche Grund dafür ist.
Hat jemand vielleicht einen Artikel oder selbst ein Beispiel parat, an denen mir die Sache vielleicht klarer wird?
Wäre sehr dankbar!
Grüße und schönen Abend noch!
-
Hä? Also wer das so behauptet wie du es hier schreibst erzählt bullshit.
-
Klar bricht "protected" die Kapselung. Beispiel:
class foo { public: // ... protected: int m_bar; }; // anderes file wo böse leute böse dinge machen: class helper : public foo { public: static int get_bar(foo const& f) { return f.m_bar; } static void set_bar(foo& f, int value) { f.m_bar = value; } }; void test() { foo f; helper::set_bar(f, 123); // wo is nu die kapselung hin? }
"protected" ist nicht mehr als "ganz nett bitte sagen". "private" ist da wesentlich effektiver, und wesentlich "deutlicher".
Um sich an "private" vorbeizuschummeln muss man sich entweder auf ganz grausame Hacks einlassen (die dann kein "sauberes" oder "korrektes" C++ mehr sind, und meist auch schlecht oder garnicht portierbar), oder etwas an den original Header Files ändern. Beides sind "extreme" Massnamen, bei denen man sich sicher 3x überlegt ob man das machen möchte.
Um "protected" auszuhebeln reicht wie oben gezeigt ein ganz einfacher "Trick", der 100% korrektes C++ ist, und vor allem keine Änderungen an den original Header Files erfordert.
-
Merci hustbaer, jetzt ist es schon klarer!
Bloß eine Frage aus Interesse, warum hast du den Code in C++ geschrieben :-P?
hustbaer schrieb:
... class helper : public foo { public: static int get_bar(foo const& f) { return f.m_bar; } static void set_bar(foo& f, int value) { f.m_bar = value; } }; void test() { foo f; helper::set_bar(f, 123); // wo is nu die kapselung hin? }
Und warum erwartest du in helper::set_bar() ein foo-Objekt?
Du bist doch selbst eins, deswegen leitest du ja ab oder? Nur so ne Frage...vielleicht willst du damit ja was bezwecken?!Grüße
-
Warum er C++ im C#-Forum schreibt weiß ich nicht, warum die Frage überhaupt im C#-Forum gestellt wird und nicht in rund um die Programmierung weiß ich aber auch nicht.
Zur zweiten Frage: Er leitet ab, da "protected" "public für abgeleitete Klassen bedeutet". Er muss also ableiten um an den Wert zu kommen. Er will aber die Werte von existierenden "foo"-Objekten verändern können und nicht nur eines neu angelegten "helper"-Objekts. Deswegen die statische Methode. Bin aber nicht sicher, ob das wirklich geht.
-
hustbaer schrieb:
class helper : public foo { public: static int get_bar(foo const& f) { return f.m_bar; } static void set_bar(foo& f, int value) { f.m_bar = value; } };
Hast du das ausprobiert? Ich bin mir ziemlich sicher, dass das nicht geht, weil protected nur den Zugriff auf Basisklasseneigenschaften im eigenen Objekt erlaubt.
-
In C# geht das so nicht. Zugriff auf den foo-Member hat tatsächlich nur ein helper-Objekt. C++ hab ich jetzt nicht versucht.
-
Oops!
Ich hab den Code in C++ geschrieben weil ich komplett übersehen habe dass ich im C# Forum binDer gepostete Code sollte in C++ funktionieren, bin ich mir ziemlich sicher - aber ich probiers aus sobald ich zuhause bin, wenn ich daran denke.
Was C# angeht: wenn C# wirklich verlangt dass das Objekt dessen "protected" Variablen man angreift auch eine Instanz der abgeleiteten Klasse ist, dann ist das zumindest schonmal viel besser. Müsste aber schätze ich trotzdem Möglichkeiten geben selbst damit die Kapselung zu brechen - schätze ich
-
hustbaer schrieb:
Der gepostete Code sollte in C++ funktionieren, bin ich mir ziemlich sicher - aber ich probiers aus sobald ich zuhause bin, wenn ich daran denke.
ok, probiert:
protected.cpp: In static member function 'static int helper::get_bar(const foo&)': protected.cpp:6: error: 'int foo::m_bar' is protected protected.cpp:14: error: within this context
Siehe auch 11.5 im Standard.
-
Asche auf mein Haupt
Ich war mir sicher das geht, geht aber nicht, auch nicht in C++.Das mit "eigenem Objekt" ist aber nicht korrekt, es muss heissen Objekt der eigenen Klasse. Also "helper" kann zwar nicht auf ein "foo" zugreifen, aber "helper" kann auf den protected "foo" Teil eines anderen Helpers zugreifen. Ob static oder nicht spielt dabei auch keine Rolle - interessant ist nur dass das Objekt wo man zugreifen will ein "helper" ist, und dass es bei einem "einfachen foo" nicht erlaubt ist.
D.h. man kann zumindest nicht auf den "protected" Teil von Objekten zugreifen deren Instanzierung man nicht kontrolliert.
Die Kapselung bricht es IMO trotzdem, bzw. protected ist trotzdem "fast public", da sich der "foo Code" nie darauf verlassen kann dass nicht irgendeine Klasse die von foo ableitet Unsinn mit den protected Variablen aufführt.
EDIT: und dieser letzte Teil gilt ganz sicher auch für C#
-
hustbaer schrieb:
Das mit "eigenem Objekt" ist aber nicht korrekt, es muss heissen Objekt der eigenen Klasse. Also "helper" kann zwar nicht auf ein "foo" zugreifen, aber "helper" kann auf den protected "foo" Teil eines anderen Helpers zugreifen. Ob static oder nicht spielt dabei auch keine Rolle - interessant ist nur dass das Objekt wo man zugreifen will ein "helper" ist, und dass es bei einem "einfachen foo" nicht erlaubt ist.
Dass man auf protected-Elemente von Objekten der eigenen Klasse zugreifen kann ist klar, sonst wäre protected ja eine Einschränkung gegenüber private. Das mit dem eigenen Objekt stimmt dennoch:
class Base { protected: int foo; }; class Derived : public Base { public: void bar() { foo = 42; } // erlaubt void bar(Base& b) { b.foo = 42; } // nicht erlaubt };
-
Nee, das mit dem "eigenen Objekt" (in C# - C++ nicht getestet) stimmt nicht.
public class ClBase { protected int foo; } class ClDerived : ClBase { public void bar() { foo = 42; } // erlaubt public void bar(ClDerived d) { d.foo = 42; } // auch erlaubt }
Hier wird NICHT auf das eigene Objekt zugegriffen, wohl aber auf ein Objekt der eigenen Klasse, und nur so geht's.
Aber mal allgemein: NATÜRLICH bricht protected die Kapselung, genau dafür ist es ja da.
Aber, zumindest in C#, kann man auch beides haben: Zugriff durch abgeleitete Klassen + Kapselung auf eigene Assembly... nämlich indem man "protected internal" verwendet. Damit hat man die Kapselung der Basisklasse gebrochen (beabsichtigt) und vermeidet einen Bruch der Kapselung der Assembly.
-
Asche auch auf mein Haupt. In C++ ist es auch so, steht auch so in §11.5.
-
Hi again,
ich habe das irgendwie immernoch nicht so überrissen. Also, dass man durch die gezeigten Beispiele auf die 'protected'-Member zugreifen kann und sie sozusagen "illegal" mit beispielsweise einem Property veröffentlicht, ist mir klar.
Aber was wäre dann die richtige Lösung, wenn ich in abgeleiteten Klassen, die 'private'-Member der Basisklasse brauche???
Irgendwie brauch ich ja Zugriff auf diese!MfG und Grüße
-
NoPlan schrieb:
Aber was wäre dann die richtige Lösung, wenn ich in abgeleiteten Klassen, die 'private'-Member der Basisklasse brauche???
lesen oder schreiben?
lesen: ein getter (bzw. in c# wohl eine property) in der basisklasse.
schreiben: gar nicht, dafür ist 'protected' da. wenn du unbedingt musst, kannst du auch einen setter in die basisklasse schreiben, der dann aber u.u. wiederum die kapselung bricht.
-
private parts schrieb:
lesen: ein getter (bzw. in c# wohl eine property) in der basisklasse.
schreiben: gar nicht, dafür ist 'protected' da. wenn du unbedingt musst, kannst du auch einen setter in die basisklasse schreiben, der dann aber u.u. wiederum die kapselung bricht.protected ist nicht dazu da, Veränderung von Daten zu verhindern.
-
NoPlan schrieb:
Aber was wäre dann die richtige Lösung, wenn ich in abgeleiteten Klassen, die 'private'-Member der Basisklasse brauche???
Irgendwie brauch ich ja Zugriff auf diese!Auf "private" gibt's in C# keinen Zugriff, da es keine "friends" gibt.
Also "protected".Allerdings....
...braucht man sowas eigentlich nicht sehr oft und
...kann man die jeweiligen Basisklassen dann fast immer "internal" machen, bzw. gibt es IIRC auch den "protected internal" Level, was meist ausreicht (denn im "eigenen" Modul kann man schonmal Dinge aufmachen/erlauben die nicht 100% deppensicher sind)EDIT: hihi, ok, das mit "protected internal" steht ja schon ein paar beiträge über diesem, sehe ich jetzt erst
-
Bashar schrieb:
protected ist nicht dazu da, Veränderung von Daten zu verhindern.
hm?
private parts schrieb:
NoPlan schrieb:
Aber was wäre dann die richtige Lösung, wenn ich in abgeleiteten Klassen, die 'private'-Member der Basisklasse brauche???
schreiben: gar nicht, dafür ist 'protected' da.
lies: wenn du die variable ändern musst, mach sie protected.
-
private parts schrieb:
Bashar schrieb:
protected ist nicht dazu da, Veränderung von Daten zu verhindern.
hm?
Protected ist dazu da die Veraenderung der Daten zu erlauben.
Private ist fuer die verhinderung.
-
private parts, du hast doch geschrieben:
lesen: ein getter[...]
schreiben: gar nicht, dafür ist 'protected' da.Da lese ich "protected heißt, dass schreiben (auch durch einen setter) tabu ist" raus. Du hättest "schreiben: ein setter" schreiben müssen, wenn es anders gemeint wäre.