Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to propagate friend for derived classes

Tags:

c++

friend

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?

like image 984
Mircea Ispas Avatar asked Dec 17 '12 14:12

Mircea Ispas


People also ask

Can a derived class be a friend?

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.

Do derived classes inherit friends?

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.

Do derived classes inherit private members?

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.

Can derived class access private members?

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.


2 Answers

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.

like image 200
Luca Davanzo Avatar answered Sep 17 '22 14:09

Luca Davanzo


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 } 
like image 23
Masked Man Avatar answered Sep 20 '22 14:09

Masked Man