我有以下(有点伪)代码,它处理2个不同(但有些类似)类型的容器,我讨厌添加和删除这些重复(以及我的实际代码中的2个搜索功能)
class PureAbstractClass
{
public:
virtual char Func() = 0;
}
class PureOpt1 : PureAbstract
{
public:
virtual int FOption1(A, B, C) = 0; // Notice 'C'
}
class PureOpt2 : PureAbstract
{
public:
virtual int FOption2(A, B, D) = 0; // Notice 'D'
}
class Handler
{
public:
void Add(PureOpt1* arg) { v1.add(arg); }
void Add(PureOpt2* arg) { v2.add(arg); }
// This is implemented using lambda
// Sorry for LINQ syntax, lambdas are too long for pseudo code
void Del1(char c) { arg = v1.find(obj => obj->Func() == c); v1.del(arg); }
void Del2(char c) { arg = v2.find(obj => obj->Func() == c); v2.del(arg); }
void Process(ch, A, B, C, D)
{
o1 = v1.Find(obj => obj->Func() == ch);
if( null == o1 )
{
o2 = v2.Find(obj => obj->Func() == ch);
if( null == o2 )
{
DoSomething();
}
else
{
o2->FOption2(A, B, D);
}
}
else
{
o1->FOption1(A, B, C);
}
}
private:
vector<PureOpt1*> v1;
vector<PureOpt2*> v2;
}
由于Handler
而无法将Process()
作为模板类。
有没有更正确的方法来实现这种代码?
答案 0 :(得分:3)
如何在班级中正确管理2个不同类型的容器?
答案仅使用1个容器。
最简单的解决方案是在基类中使用纯粹的虚拟方法:
class PureAbstractClass
{
public:
virtual char Func() = 0;
virtual int FOption(A, B, C, D) = 0;
}
然后两个孩子都覆盖FOption()
并忽略他们不需要的参数。可能有更好的解决方案,但您没有提供足够的信息。你的解决方案 - 将它们放在两个独立的容器中可能是最糟糕的。正如您所看到的solution
与继承冲突一样(您删除了继承并使两个子项成为独立类,并且代码中不会发生任何变化)。或者,您可以使用dynamic_cast
,但使用它通常会显示错误的程序设计:
PureAbstractClass *o = find( ... );
if( !o ) {
DoSomething();
return;
}
if( PureOpt1 *po1 = dynamic_cast<PureOpt1 *>( o ) )
po1->FOption1( A, B, C );
else {
if( PureOpt2 *po2 = dynamic_cast<PureOpt2 *>( o ) )
po2->FOption2( A, B, D );
else
// something wrong object is not PureOpt1 nor PureOpt2
}
注意:在这种情况下,FOption1()
和FOption2()
完全没有必要是虚拟的。你不应该忘记将虚拟析构函数添加到基类。
或者你可以使用boost::variant
和访问者模式,在这种情况下你也不需要继承,但你可以使你的代码通用。
答案 1 :(得分:0)
如果可能,FOption1 / 2为int Func(数据常量和数据)。然后,您创建数据并将其传递给它。数据可以包含四个不同的信息,C和D是可选的。然后,Func的具体实现可以根据需要处理该数据