views:

129

answers:

3

I have an interface class MyFunction. There are three functions in this class with the following signatures:

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;

Now, any implementation of MyFunction will only need to implement one of these functions depending on what type of value it needs to return. But I'll have to implement all 3 functions even if the other two functions are like this:

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

which doesnt look so good. Or, I can declare all three functions like this in the interface:

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;}

Which also looks ugly. What is the less ugly of these two? Or is there a better way to do this?

EDIT:

On D Krueger's method :

#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);
}

Looks like specialization does not apply across classes though derived. As template functions can't be virtual, this is a hopeless situation it seems.

+2  A: 

It's a sign that your interface-design could need to be refactored, when the classes implementing the interface did not need the whole amount of methods in it. Perhaps you could divide this interface into 3 interfaces.

Another possibility would be to create a wrapper-interface from that, which returns default values for the unneeded 2 methods. But in this case you would end up with 3 interfaces as well (and the original parent-interface -> 4 interfaces total). This solution would be acceptable if you have no possibility of changing the original interface.

MOnsDaR
Yes I can declare a `template<typename T> class MyFunction` and use the three specializations. But, the problem is I have to create objects from all the three types from a factory and store in a collection. Or perhaps I will have to give it up.
nakiya
Then I would prefer the first solution (implementing the methods in the class, returning false). An interface whose methods are not needed to be implemented isn't an interface in my opinion.
MOnsDaR
+3  A: 

Since there is a one-to-one mapping between the types used in Eval() and the number of implementations, a template member function should work.

class MyFunction {

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

Then implement the specializations for the types that shouldn't return false.

This requires only the single generic implementation to return false and the three implementations that would be needed in any case.

D Krueger
+1 Good answer. However, Implementations of `MyFunction` will reside in a shared object. does this cause a problem?
nakiya
If the implementations need access to the same member variables (to save state for example) then it could be a problem. Otherwise, it should be fine.
D Krueger
Not very clear to me. Can you please explain a little more?
nakiya
This method does not work :(. See my edit.
nakiya
Now it is clear to me. For template specialization to work in this case, the specializations have to be in the base class because that is what the compiler sees. Otherwise, we'd be asking for template functionality at run time (Derived class is only available then). :)
nakiya
A: 

I think you might be better off declaring a single pure virtual method to override, but have it return a discriminated union or variant/any type in that first argument. Then each derived class can return the type it wants. With your current way, you were going to need to make a decision on which method to call. With a discriminated union, you'll only call the one method, but make the decision about what to do with it after it returns.

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;
}

becomes something like:

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;
}

Obviously I've skipped the error checking and the like, but it's pretty similar to what I think you're planning to do.

xscott