如何从界面中删除不需要的功能

时间:2010-10-21 04:49:16

标签: c++ coding-style

我有一个接口类MyFunction。此类中有三个函数,具有以下签名:

virtual bool Eval(int& iReturnVal, size_t szArgumentCount, list<Param> lParameterList) = 0;
virtual bool Eval(double& dReturnVal, size_t szArgumentCount, list<Param> lParameterList) = 0;
virtual bool Eval(char*& zReturnVal, size_t szArgumentCount, list<Param> lParameterList) = 0;

现在,MyFunction的任何实现只需要实现其中一个函数,具体取决于它需要返回的值类型。但即使其他两个函数是这样的,我也必须实现所有3个函数:

virtual bool Eval(double& dReturnVal, size_t szArgumentCount, list<Param> lParameterList){return false;}

看起来不那么好。或者,我可以在界面中声明所有这三个函数:

virtual bool Eval(int& iReturnVal, size_t szArgumentCount, list<Param> lParameterList){return false;}
virtual bool Eval(double& dReturnVal, size_t szArgumentCount, list<Param> lParameterList){return false;}
virtual bool Eval(char*& zReturnVal, size_t szArgumentCount, list<Param> lParameterList){return false;}

哪个看起来也很难看。这两个中不那么丑陋的是什么?或者有更好的方法吗?

编辑:

关于D Krueger的方法:

#include <iostream>

using namespace std;

class Base
{
    public:
        template<typename T>
            void F(T){cout << "Type T" << endl;}
};

class Imp : public Base
{
    public:
        template<int>
            void F(int){cout << "Type int" << endl;}
};

int main(int argc, char** argv)
{
    Base* pB;
    Imp oI;
    pB = &oI;

    pB->F(1);
}

看起来虽然派生的特殊化不适用于各个类。由于模板功能不能是虚拟的,这似乎是一种无望的情况。

3 个答案:

答案 0 :(得分:3)

由于Eval()中使用的类型与实现数之间存在一对一的映射,因此模板成员函数应该有效。

class MyFunction {

    template <class T>
    bool Eval(T& returnVal, size_t szArgumentCount, list<Param> lParameterList) 
        { return false; }
};

然后为不应返回false的类型实现特化。

这只需要单个泛型实现返回false以及在任何情况下都需要的三个实现。

答案 1 :(得分:2)

当实现接口的类不需要其中的全部方法时,这表明您的接口设计可能需要重构。也许您可以将此接口划分为3个接口。

另一种可能性是从中创建一个包装器接口,它返回不需要的2个方法的默认值。但在这种情况下,你最终会得到3个接口(原始的父接口 - 总共4个接口)。如果您无法更改原始界面,则可以接受此解决方案。

答案 2 :(得分:0)

我认为你可能最好声明一个纯虚方法来覆盖,但让它在第一个参数中返回一个有区别的联合或变体/任何类型。然后每个派生类都可以返回它想要的类型。按照目前的方式,您需要决定调用哪种方法。使用一个有区别的联合,你只会调用一个方法,但在它返回后决定如何处理它。

double dd;
int ii;
char* ss;
switch (ptr->type) {
    case DOUBLE:  ptr->Eval(&dd, ...); break;
    case INTEGER: ptr->Eval(&ii, ...); break;
    case STRING:  ptr->Eval(&ss, ...); break;
}

变得像:

double dd;
int ii;
char* ss;
variant vv;
ptr->Eval(&vv, ...);
switch (vv.type) {
    case DOUBLE:  dd = vv.dd; break;
    case INTEGER: ii = vv.ii; break;
    case STRING:  ss = vv.ss; break;
}

显然我已经跳过错误检查等,但它与我认为你打算做的非常相似。