Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Derived class instances to share the same base class instance

Say I have a Proc class with the following interface:

class Proc
{
public:
  void process();
protected:
  virtual void do_process() = 0;
private:
  int m_counter;
};

Now, say I have two derived classes that implement Proc interface.

class DerivedProc1:
  public Proc
{
protected:
  virtual void do_process();
};

class DerivedProc2:
  public Proc
{
protected:
  virtual void do_process();
};

Now I generate two derived classes as:

Proc* dp1 = new  DerivedProc1();
Proc* dp2 = new  DerivedProc2();

Question

I would like both dp1 and dp2 to share the same base class instance.
The reason I need that is because Proc::m_counter must be the same in both processor, meaning, changing its value in one processor must be "seen" by the other one. Of course, Proc::m_counter is just an example of a variable I'd like share.
what is the standard approach for that issue?

Notes

I'm not looking for a quick fix for the issue. meaning:

  1. making Proc::m_counter static is not desired. I still need it to be bound to a specific Proc instance.
  2. I don't want to hold m_counter outside of Proc and pass is as a reference to proc
like image 842
idanshmu Avatar asked Mar 04 '14 08:03

idanshmu


People also ask

Can we assign base class instance to derived class?

In C++, a derived class object can be assigned to a base class object, but the other way is not possible.

Can a derived class be a friend of base?

Inheritance and Friendship in C++If a base class has a friend function, then the function doesn't become a friend of the derived class(es). For example, the following program prints an error because the show() which is a friend of base class A tries to access private data of derived class B.

Can a class be both a base class and a derived class?

A derived class can have only one direct base class.

Can a derived class have more than one base class?

You can derive a class from any number of base classes. Deriving a class from more than one direct base class is called multiple inheritance. The order of derivation is relevant only to determine the order of default initialization by constructors and cleanup by destructors.


4 Answers

As stated it is not possible. The following requirements are mutually contradictory:

  • The count is a data member of an instance of DerivedProc1, not "outside of Proc".
  • The count is a data member of an instance of DerivedProc2.
  • The instance of DerivedProc1 and the instance of DerivedProc2 are allocated by separate calls to new, that is to say they are different most-derived objects.

Different most-derived objects cannot share a data member. The reason is that a most-derived object is defined to occupy its own region of memory. Only subobjects of the same most-derived object can share members.

If you're willing to relax the "store outside" restriction then the solution is "obvious": have each object hold a shared_ptr to something with the count in it. Pass the same count-holding object to the constructors of whatever objects you wish to share a count. The only thing making this question difficult is your restriction on where the count is located in memory.

If you're willing to relax the "separate new calls" restriction then you could use virtual inheritance and construct both Proc objects as base-class subobjects of a single most-derived object:

class DerivedProc1 : public virtual Proc { ... };
class DerivedProc2 : public virtual Proc { ... };

class CombinedProc : public DerivedProc1, DerivedProc2 { ... };

CombinedProc *dp0 = new CombinedProc();
DerivedProc1 *dp1 = dp0;
DerivedProc2 *dp2 = dp0;

Since none of the classes has a virtual destructor, you must use dp0 (and not dp1 or dp2) to delete the object. If you give Proc a virtual destructor then you could use any one (and only one) of them.

I would not advise using virtual inheritance unless you properly understand it. So, since you're going to have to relax one of the requirements I'd normally say that the standard approach is relaxing the first: store the count in a separate object outside of the two objects.

like image 50
Steve Jessop Avatar answered Oct 10 '22 21:10

Steve Jessop


Don't use inheritance. Instead, give DerivedProc1 and DerivedProc1 a member pointer to a Proc instance and construct both objects with a pointer to a single Proc object.

Something like this:

class DerivedProc1
{
protected:
  Proc *proc;
  void do_process(){
     proc->process();
  }
public:
  DerivedProc1(Proc *proc):proc(proc){}
};

Probably best to use std::shared_ptr<Proc> over raw pointers as derived class members.

like image 28
Marc Claesen Avatar answered Oct 10 '22 22:10

Marc Claesen


Instead of having a base class with a shared resource, have a base class just for the interface, and then a separate object that is shared between the classes, which contains the counter.

like image 1
Some programmer dude Avatar answered Oct 10 '22 22:10

Some programmer dude


First, do_process must be virtual and the DerivedProcX needs to derive from Proc.

To share the counter you can declare it as static and make the base class a template, something like this:

class BaseProc {};

template <int n> class Proc : BaseProc
{
    virtual void do_process() = 0;
    static int m_counter;
}

template <int n> class DerivedProc1 : public Proc<n>
{
    void do_process() {}
}

template <int n> class DerivedProc2 : public Proc<n>
{
    void do_process() {}
}

int main()
{
    // dp1 and dp2 share the same counter
    Proc<1>* dp1 = new DerivedProc1<1>;
    Proc<1>* dp2 = new DerivedProc2<1>;

    // dp3 and dp4 share the same counter, but not the same as dp1 and dp2
    BaseProc* dp3 = new DerivedProc1<2>;
    BaseProc* dp4 = new DerivedProc2<2>;
}

Of course this solution assumes that you know at compile time what instances will need to share the same counter.

like image 1
Loghorn Avatar answered Oct 10 '22 22:10

Loghorn