假设我有一个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();
我希望dp1
和dp2
与共享相同的基类实例。
我需要的原因是因为Proc::m_counter
在两个处理器中必须相同,这意味着,在一个处理器中更改其值必须由另一个处理器“看到”。当然,Proc::m_counter
只是我想分享的变量的一个例子
这个问题的标准方法是什么?
我不是在寻找快速解决问题的方法。含义:
Proc::m_counter
static
。我仍然需要它绑定到特定的Proc
实例。 m_counter
置于Proc
之外,而传递则是proc
答案 0 :(得分:5)
如上所述,这是不可能的。以下要求相互矛盾:
DerivedProc1
实例的数据成员,而不是“{1}}之外”。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;
(而不是dp0
或dp1
)来删除对象。如果你给dp2
一个虚拟析构函数,那么你可以使用它们中的任何一个(并且只有一个)。
除非您正确理解,否则我不建议使用虚拟继承。因此,由于您将不得不放松其中一个要求,我通常会说标准方法是放松第一个:将计数存储在两个对象之外的单独对象中。
答案 1 :(得分:3)
不要使用继承。相反,为DerivedProc1
和DerivedProc1
提供指向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);
这两个好处: - 界面已被保留。 - 计数器数据已经共享(没有静态,它是特定于实例的)。
希望这有帮助。