2010-10-21 3 views
5

У меня есть класс интерфейса 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;} 

Который также выглядит уродливым. Какое менее уродливое из этих двух? Или есть лучший способ сделать это?

EDIT:

О методе D Крюгера:

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

Похоже специализации не распространяется по классам, хотя получены. Поскольку функции шаблонов не могут быть виртуальными, это кажется безнадежной ситуацией.

+2

Возможно, что-то похоже на 'boost :: variant ' для параметра одной функции. – GManNickG

+0

нет повышение пожалуйста. :). Невозможно использовать.Я хочу что-то, что могу построить самостоятельно. – nakiya

+1

Если ваш интерфейс имеет другие чистые виртуальные функции, перейдите со вторым. Вы не получите больше «чистоты» от более чистых виртуальных функций, и вы получите эффект, который вы желаете. Если вы хотите, чтобы вы могли обработать какой-то трюк, чтобы убедиться, что хотя бы одна из функций 'Eval()' может возвращать true, но это может быть черная магия. –

ответ

2

Это знак того, что ваш интерфейс-дизайн может понадобиться реорганизовать, когда классы, реализующие интерфейс, не нуждаются в целом ряде методов в нем. Возможно, вы можете разделить этот интерфейс на 3 интерфейса.

Другой возможностью было бы создание интерфейса-оболочки из этого, который возвращает значения по умолчанию для ненужных методов 2. Но в этом случае вы также получите 3 интерфейса (и исходный родительский интерфейс -> всего 4 интерфейса). Это решение было бы приемлемым, если у вас нет возможности изменить оригинальный интерфейс.

+0

Да Я могу объявить «шаблон класс MyFunction' и использовать три специализации. Но проблема в том, что мне нужно создавать объекты от всех трех типов от фабрики и магазина в коллекции. Или, возможно, мне придется отказаться от нее. – nakiya

+1

Тогда я предпочел бы первый (реализация методов в классе, возврат false). Интерфейс, методы которого не нужны для реализации, не является, на мой взгляд, интерфейсом. – MOnsDaR

3

Поскольку существует взаимно однозначное сопоставление между типами, используемыми в Eval(), и количеством реализаций, функция члена шаблона должна работать.

class MyFunction { 

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

Затем выполните специализации для типов, которые не должны возвращать false.

Для этого требуется только одна общая реализация, чтобы возвращать false и три реализации, которые необходимы в любом случае.

+0

+1 Хороший ответ. Однако реализации «MyFunction» будут находиться в общем объекте. это вызывает проблему? – nakiya

+0

Если для реализации требуется доступ к тем же переменным-членам (например, для сохранения состояния), это может быть проблемой. В противном случае это должно быть хорошо. –

+0

Мне не очень понятно. Не могли бы вы объяснить немного больше? – nakiya

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

Очевидно, я пропустил проверку ошибок и т.п., но это очень похоже на то, что я думаю, что вы собираетесь делать.

Смежные вопросы