派生类实例以共享相同的基类实例

时间:2014-03-04 08:55:40

标签: c++ inheritance

假设我有一个Proc类,其中包含以下界面:

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

现在,假设我有两个实现Proc接口的派生类。

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

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

现在我生成两个派生类:

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

问题

我希望dp1dp2共享相同的基类实例
我需要的原因是因为Proc::m_counter在两个处理器中必须相同,这意味着,在一个处理器中更改其值必须由另一个处理器“看到”。当然,Proc::m_counter只是我想分享的变量的一个例子 这个问题的标准方法是什么?

注释

我不是在寻找快速解决问题的方法。含义:

  1. 不希望制作Proc::m_counter static。我仍然需要它绑定到特定的Proc实例。
  2. 我不想将m_counter置于Proc之外,而传递则是proc
  3. 的参考

5 个答案:

答案 0 :(得分:5)

如上所述,这是不可能的。以下要求相互矛盾:

  • 该计数是DerivedProc1实例的数据成员,而不是“{1}}之外”。
  • count是Proc
  • 实例的数据成员
  • DerivedProc2的实例和DerivedProc1的实例是通过对DerivedProc2的单独调用分配的,也就是说它们是最不同的派生对象。

不同的大多数派生对象无法共享数据成员。原因是定义了一个派生程度最高的对象以占用其自己的内存区域。只有同一个派生对象的子对象才能共享成员。

如果你愿意放宽“限制存储”限制,那么解决方案是“显而易见的”:让每个对象持有一个new来计算其中的数量。将相同的计数保持对象传递给您希望共享计数的任何对象的构造函数。使这个问题变得困难的唯一方法是限制计数在内存中的位置。

如果您愿意放宽“单独的shared_ptr调用”限制,那么您可以使用虚拟继承并将两个new对象构造为单个最派生对象的基类子对象:< / p>

Proc

由于没有类具有虚拟析构函数,因此必须使用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; (而不是dp0dp1)来删除对象。如果你给dp2一个虚拟析构函数,那么你可以使用它们中的任何一个(并且只有一个)。

除非您正确理解,否则我不建议使用虚拟继承。因此,由于您将不得不放松其中一个要求,我通常会说标准方法是放松第一个:将计数存储在两个对象之外的单独对象中。

答案 1 :(得分:3)

不要使用继承。相反,为DerivedProc1DerivedProc1提供指向Proc实例的成员指针,并使用指向单个Proc对象的指针构造两个对象。

这样的事情:

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

可能最好使用std::shared_ptr<Proc>而不是原始指针作为派生类成员。

答案 2 :(得分:1)

不是拥有带共享资源的 base 类,而是只为接口创建一个基类,然后在包含计数器的类之间共享一个单独的对象。

答案 3 :(得分:1)

首先,do_process必须为virtual,而DerivedProcX需要来自Proc

要共享计数器,您可以将其声明为static并将基类设为模板,如下所示:

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>;
}

当然,此解决方案假设您在编译时知道共享同一个计数器需要哪些实例。

答案 4 :(得分:0)

你应该重新考虑你的设计。

据我所知,你需要一种包含继承和组合的混合设计(如下所示)。

class CounterHolder
{
public:
    int m_counter;
};

class Proc
{
public:
    Proc(CounterHolder *counterHolder)
    {
        m_conterHolder = counterHolder;
    }

    void process();
protected:
    virtual void do_process() = 0;
private:
    CounterHolder *m_counterHolder;
};

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

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

现在,您有继承以及共享数据的优惠(由于撰写)

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

这两个好处:   - 界面已被保留。   - 计数器数据已经共享(没有静态,它是特定于实例的)。

希望这有帮助。