虚函数的参数未在所有子类中使用;有没有更好的设计方法?

时间:2012-03-14 16:58:05

标签: c++ oop inheritance

我正在编写一些相关的C ++类,而且我在设计特定的继承函数时遇到了一些麻烦。

具体来说,这些类都是树上的“操作”,我需要能够在树上执行一组任意树操作。我在每个类中都有一个名为ExecuteOperation()的函数。

问题在于,在某些课程中,我需要比其他课程更多的补充信息。现在,我只是将额外的信息传递给所有类,其抽象基类定义如下:

class BasicOperation  {
    public:
    //...
        virtual void ExecuteOperation(Tree* tree, multimap<int,Foo*> extra1, multimap<int,Foo*> extra2) = 0;
    //...
}

BasicOperation子类的后代“SpecialOperation”需要参数extra1和extra2,而“NonspecialOperation”的后代根本不使用这些参数。

ExecuteOperation的调用者通常是这样的:

Tree* tree;
std::vector<BasicOperation*> operations;
//...
for(size_t i=0;i<operations.size();i++)  {
    operations[i]->ExecuteOperation(tree,extra1,extra2);
}

extra1和extra2的填充取决于特定的树,可能是计算密集型的(最好不要在每次ExecuteOperation调用中重新创建它们)。

有没有更好的方法来设计它,以便只有SpecialOperation对象获取传递给它们的参数?或者将未使用的参数传递给像NonspecialOperation这样的类一样好吗?

使用两个不使用的参数定义NonspecialOperation :: ExecuteOperation()感觉很奇怪。

到目前为止,我唯一想到的是将SpecialOperation对象的每个指针都返回给调用者,并将额外的信息存储在调用者对象中。我真的不喜欢这个解决方案,因为extra1和extra2太依赖于当前的状态;除了并行化问题,这种设置只是“感觉”错误。

另外,将tree,extra1和extra2包装在另一个结构中以传递给ExecuteOperation可能会使它看起来更干净,并且有意义,因为extra1和extra2是树的额外描述符,但我不知道这是否是最佳解决方案:

struct TreeEx  {
    Tree* tree;
    multimap<int,Foo*> extra1, extra2;
};
//in BasicOperation:
virtual void ExecuteOperation(TreeEx* tree_with_info) = 0;

2 个答案:

答案 0 :(得分:3)

使用

  

virtual void ExecuteOperation(Tree * tree);

没有额外的论据。

BasicOperation派生的类中通过构造函数传递额外的参数。 向树添加允许BasicOperation提取所需数据的方法。

另见Command模式和Visitor模式

- 编辑 -

  

额外的参数特别适用于树

在基础Tree类中创建一个虚拟函数,用于创建所需的命令

class Tree{
public:
    virtual BasicOperation* makeSpecificTreeOperation() = 0;
    virtual ~Tree();
};
  • 用于每种类型的命令。

在儿童中重写

 class DerivedTree: public Tree{
    ...
    virtual BasicOperation* makeSpecificTreeOperation();
    ...
 };

 class DerivedCommand: public BasicOperation{
 ....
 public:
    DerivedCommand(ExtraTreeData& extraData);
 };

 BasicOperation* DerivedTree::maksSpecificTreeOperation(){
     return new DerivedCommand(this->extraData);
 }

并返回所需的命令类,使用构造函数将数据传递到命令中。

请参阅Abstract Factory模式和Builder模式。

答案 1 :(得分:1)

如果是通过接口,则将引用返回给调用者是很干净的。因此,您可以反转依赖关系。你会:

virtual void ExecuteOperation(ICaller* caller)

然后,您可以在实际调用者中实现它(但您在上下文中显然存在并发问题)或在专用类中实现它。你通过这种方式减少耦合,这是一件好事。当然,ICaller会为extra1extra2提供仅针对相关BasicOperation实现调用的getter。