2010-10-21 13 views
5

Mam interfejs klasy MyFunction. Istnieją trzy funkcje w tej klasie z następujących podpisów:Jak usunąć niechciane funkcje z interfejsu

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; 

Teraz, każde wdrożenie MyFunction będą potrzebne tylko w celu realizacji jednego z tych funkcji, w zależności od typu wartości musi powrócić. Ale będę musiał wdrożyć wszystkie 3 funkcje, nawet jeśli pozostałe dwie funkcje są takie:

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

co nie wygląda tak dobrze. Lub, mogę zadeklarować wszystkie trzy takie funkcje w interfejsie:

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

Co również wygląda brzydko. Co jest mniej brzydkiego z tych dwóch? Czy istnieje lepszy sposób to zrobić?

EDIT:

Na Metoda D Kruegera:

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

Wygląda specjalizacji nie ma zastosowania w poprzek klas choć pochodzą. Ponieważ funkcje szablonu nie mogą być wirtualne, wydaje się, że jest to sytuacja beznadziejna.

+2

Może to, czego szukasz, to coś w rodzaju 'boost :: variant ' dla parametru pojedynczej funkcji. – GManNickG

+0

Proszę nie dopuścić. :). Nie można go użyć.Chcę czegoś, co mogę zbudować na własną rękę. – nakiya

+1

Jeśli twój interfejs ma inne czyste funkcje wirtualne, idź z drugim. Nie uzyskasz więcej "czystości" od bardziej czystych funkcji wirtualnych, a uzyskasz pożądany efekt. Jeśli chcesz, możesz wymyślić jakąś sztuczkę, aby upewnić się, że co najmniej jedna z funkcji 'Eval()' może zwrócić true, ale może to być czarna magia. –

Odpowiedz

2

To znak, że twój projekt interfejsu może wymagać ponownego przetworzenia, gdy klasy implementujące interfejs nie potrzebują całej ilości metod. Być może mógłbyś podzielić ten interfejs na 3 interfejsy.

Inną możliwością jest utworzenie z tego interfejsu wrappera, który zwraca domyślne wartości dla niepotrzebnych 2 metod. Ale w tym przypadku otrzymasz również 3 interfejsy (i oryginalny interfejs-rodzic -> 4 interfejsy łącznie). To rozwiązanie byłoby do przyjęcia, jeśli nie masz możliwości zmiany oryginalnego interfejsu.

+0

Tak Mogę zadeklarować 'szablon class MyFunction' i użyć trzech specjalizacji, ale problemem jest to, że muszę tworzyć obiekty od wszystkich trzech typów z fabryki i sklepu w kolekcji, a może będę musiał zrezygnować z tego – nakiya

+1

Wtedy wolałbym pierwsze tak lution (implementacja metod w klasie, zwracanie false). Interfejs, którego metody nie są potrzebne do wdrożenia, moim zdaniem nie jest interfejsem. – MOnsDaR

3

Ponieważ istnieje odwzorowanie typu jeden-do-jednego między typami użytymi w pliku Eval() i liczbą implementacji, powinna działać funkcja elementu szablonu.

class MyFunction { 

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

Następnie zaimplementuj specjalizacje dla typów, które nie powinny zwracać fałszu.

Wymaga to tylko jednej ogólnej implementacji, aby zwrócić fałsz i trzy implementacje, które byłyby potrzebne w każdym przypadku.

+0

+1 Dobra odpowiedź. Jednak implementacje 'MyFunction' będą znajdować się we współdzielonym obiekcie. Czy to powoduje problem? – nakiya

+0

Jeśli implementacje wymagają dostępu do tych samych zmiennych składowych (na przykład do zapisania stanu), może to stanowić problem. W przeciwnym razie powinno być dobrze. –

+0

Niezbyt jasne dla mnie. Czy możesz wyjaśnić trochę więcej? – nakiya

0

Myślę, że może ci się lepiej udać deklarowanie pojedynczej czystej wirtualnej metody, aby ją zastąpić, ale niech zwróci ona dyskryminowaną unię lub wariant/dowolny typ w tym pierwszym argumencie. Następnie każda klasa pochodna może zwrócić typ, który chce. W twoim obecnym stanie będziesz musiał podjąć decyzję, którą metodę wybrać. W przypadku dyskryminowanej unii, nazwiesz tylko jedną metodę, ale podejmiesz decyzję, co z nią zrobić po powrocie.

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

staje się czymś w rodzaju:

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

Oczywiście ja skoczyliśmy sprawdzanie błędów i tym podobne, ale to jest bardzo podobne do tego, co myślę, że masz zamiar zrobić.

Powiązane problemy