I want to have a class hierarchy and be able to create objects from it only inside a Factory.
Example:
class Base { protected: Base(){}; virtual void Init(){}; friend class Factory; }; class SomeClass : public Base { public://I want protected here! Now it's possible to call new SomeClass from anywhere! SomeClass(){}; void Init(){}; }; class Factory { public: template<class T> T* Get() { T* obj = new T(); obj->Init(); return obj; } }; int main() { Factory factory; SomeClass *obj = factory.Get<SomeClass>(); }
My problem is that I want to be able to make objects only from Factory, but I don't want to declare friend class Factory
in every class derived from Base.
Is there any way to propagate friend in derived classes? Is there any other way to achieve this behavior?
It is not possible. As others have said friendship is not inherited. An alternative is to make all class hierarchy constructors protected and add the factory function/class as friend to all the classes you're interested in.
The answer is very simple: no, subclasses do not inherit friend associations. A friend can only access the private members of the class the association is declared in, not those of parents and/or children of that class.
The derived class doesn't "inherit" the private members of the base class in any way - it can't access them, so it doesn't "inherit" them.
Private members of the base class cannot be used by the derived class unless friend declarations within the base class explicitly grant access to them.
No, it's deliberately impossibile.
Is an issue by encapsulation.
Suppose to have a class "PswClass" that manage any password, that is cascade friend with other class: if I inherit from PswClass:
class Myclass : public PswClass { ....... }
In this way I can, maybe, have access to field that it would be private.
Friendship is neither inherited nor transitive, as described here: friend class with inheritance.
After a little experimentation, and making some use of this hack How to setup a global container (C++03)?, I think I have found a way give the "factory" unique rights to create the objects.
Here's a quick and dirty code. (Scroll towards the bottom to see the hack.)
class Object {}; class Factory { public: // factory is a singleton // make the constructor, copy constructor and assignment operator private. static Factory* Instance() { static Factory instance; return &instance; } public: typedef Object* (*CreateObjectCallback)(); private: typedef std::map<int, CreateObjectCallback> CallbackMap; public: // Derived classes should use this to register their "create" methods. // returns false if registration fails bool RegisterObject(int Id, CreateObjectCallback CreateFn) { return callbacks_.insert(CallbackMap::value_type(Id, createFn)).second; } // as name suggests, creates object of the given Id type Object* CreateObject(int Id) { CallbackMap::const_iterator i = callbacks_.find(Id); if (i == callbacks_.end()) { throw std::exception(); } // Invoke the creation function return (i->second)(); } private: CallbackMap callbacks_; }; class Foo : public Object { private: Foo() { cout << "foo" << endl; } private: static Object* CreateFoo() { return new Foo(); } public: static void RegisterFoo() { Factory::Instance()->RegisterObject(0, Foo::CreateFoo); } }; class Bar : public Object { private: Bar() { cout << "bar" << endl; } private: static Object* CreateBar() { return new Bar(); } public: static void RegisterBar() { Factory::Instance()->RegisterObject(1, Bar::CreateBar); } }; // use the comma operator hack to register the create methods int foodummy = (Foo::RegisterFoo(), 0); int bardummy = (Bar::RegisterBar(), 0); int main() { Factory::Instance()->CreateObject(0); // create foo object Factory::Instance()->CreateObject(1); // create bar object }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With