Wie Zugriff limitieren?
-
Hallo,
ich habe eine abstrakte Factory Klasse und verschiedene konkrete Subklassen, sagen wir mal FooFactory. Die Factory kann verschiedene Objekte vom Typ A, B, C erzeugen.
Wenn ein Objekt erzeugt wird, soll es sich bei der Factory registrieren, z.B.:A::A() { ... mFactory->register(this); }Das Problem: Factory::register() sollte nur von A,B,C Klassen aufgerufen werden können, sprich: private sein. Nur kann ich nicht in class Factory einfach friend class A machen, da die konkreten Methoden in Factory pure virtual sind und erst in den konkreten Factorys implementiert werden.
Also müsste ich in jede konkrete Factory, wie z.b. FooFactory ein friend class A; friend class B; etc setzen.Geht das irgendwie schöner?
-
Mach register nicht direkt virtuell, sondern eine Funktion, die die virtuelle aufruft. Dann kannst du auch das mit dem friend dort implementieren.
Das ist sogar ein übliches Pattern, habe allerdings vergessen wie es heisst. ^^
-
Non-virtual interface, kurz NVI.
-
Ah, genau das wars. ^^
-
Das sieht klasse aus, danke!
Dann habe ich gleich noch eine ähnliche Frage:
Sagen wir die abstrakte Factory hat createXY Methoden:
virtual A* Factory::createA(string) = 0; virtual B* Factory::createB(string) = 0;A und B sind ebenfalls abstrakte Klassen. Konkrete Factories geben dann konkrete Objekte zurück:
virtual AFoo* FooFactory::createA(string); virtual BFoo* FooFactory::createB(string);Ich will nun, dass NUR Factories A und B Objekte (sprich AFoo, BFoo etc.) erzeugen kann. Wie kann man das sicherstellen?
Ich kann ja nicht einfach Factory zu einem friend von A machen, denn wird ja
ein AFoo von FooFactory erzeugt. Sprich ich müsste JEDER konkreten Objektklasse (AFoo, BFoo...) ihre jeweilige konkrete Factory (FooFactory etc.) als friend geben.
Klingt schlecht. WIe könnte man das machen?
-
Du kannst beim Registrieren der Factory einen "Creator" übergeben. Dieser ist z.B. eine private statische Method die den privaten Ctor aufruft und die einzige Möglickeit das jeweilge Objekt zu erstellen.
-
drakon schrieb:
Mach register nicht direkt virtuell, sondern eine Funktion, die die virtuelle aufruft. Dann kannst du auch das mit dem friend dort implementieren.
Das ist sogar ein übliches Pattern, habe allerdings vergessen wie es heisst. ^^Mir is grad aufgefallen, dass das nicht funktioniert.
Ich habe es jetzt so (Frage im Code):class Factory { private: friend class A; // A soll registerA() aufrufen dürfen void registerA(A* a) { registerAImpl(a); } virtual void registerAImpl(A* a) = 0; }; class FooFactory : public Factory { private: virtual void registerAImpl(A* a) { ... } }; class A { Factory* mCreator; public: virtual void method() = 0; // A ist abstrakt }; class AFoo : public A { public: void init() { mCreator->registerA(this); // Das hier geht nicht! Den nur A ist friend der Factory. Ich müsste in Factory die konkreten Subklassen //(AFoo, BFoo etc) als friend deklarieren. Geht das anders? } }
-
Dann lass das registrieren halt A machen, anstatt AFoo.
Du solltest auch eher Konstruktoren verwenden und auch Überladung wäre etwas, womit du deinen Code schöner machen kannst.
-