我有一个接口类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);
}
看起来虽然派生的特殊化不适用于各个类。由于模板功能不能是虚拟的,这似乎是一种无望的情况。
答案 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;
}
显然我已经跳过错误检查等,但它与我认为你打算做的非常相似。