Przeczytałem tutaj kilka pytań dotyczących SO na ten temat, który wydaje mi się jeszcze niejasny. Dopiero co zacząłem uczyć się C ++ i nie studiowałem jeszcze szablonów, przeciążenia operatorów i tym podobnych.
Czy istnieje prosty sposób na przeciążenie
class My {
public:
int get(int);
char get(int);
}
bez szablonów lub dziwnego zachowania? czy powinienem po prostu
class My {
public:
int get_int(int);
char get_char(int);
}
?
c++
overloading
But
źródło
źródło
int
wartością zwracaną będzie wyglądać tak(int)get(9)
ichar
tak(char)get(9)
.Odpowiedzi:
Nie, nie ma. Nie można przeciążać metod opartych na zwracanym typie.
Rozwiązanie przeciążenia uwzględnia sygnaturę funkcji . Podpis funkcji składa się z:
A oto cytat:
1.3.11 podpis
Opcje:
1) zmień nazwę metody:
class My { public: int getInt(int); char getChar(int); };
2) parametr out:
class My { public: void get(int, int&); void get(int, char&); }
3) szablony ... w tym przypadku przesada.
źródło
My::get<T>(int)
. Jest to poprawna alternatywa _jeśli 1) musisz obsługiwać wiele różnych typów, wszystkie z tym samym podstawowym kodem (np.boost::lexical_cast<T>( someStringValue )
Lub musisz mieć możliwość wywołania tych funkcji z innego szablonu (myMy.get<T>( i )
gdzieT
jest argumentem tego innego szablonu W przeciwnym razie, jak mówi Luchian, są przesadąmy.get(0);
do kompilatora, nie będziesz miał możliwości zdecydowania, który fragment kodu wykonać.void foo(int x = 0) {} void foo(double x = 0) {}
powinno być niedozwolone. Tak jednak nie jest. Tylko w przypadku, gdy kompilator naprawdę nie może odróżnić (foo()
), pojawi się błądJest to możliwe, ale nie jestem pewien, czy jest to technika, którą poleciłbym początkującym. Podobnie jak w innych przypadkach, gdy chcesz, aby wybór funkcji zależał od sposobu wykorzystania wartości zwracanej, używasz serwera proxy; najpierw zdefiniuj funkcje, takie jak
getChar
igetInt
, a następnie rodzaj,get()
który zwraca proxy w następujący sposób:class Proxy { My const* myOwner; public: Proxy( My const* owner ) : myOwner( owner ) {} operator int() const { return myOwner->getInt(); } operator char() const { return myOwner->getChar(); } };
Rozszerz go na tyle typów, ile potrzebujesz.
źródło
std::string
, a proxy oferuje tylkooperator char const*()
, to nie zadziała.Nie, nie możesz przeciążać zwracanego typu; tylko według typów parametrów i kwalifikatorów const / volatile.
Jedną z możliwości byłoby „zwrócenie” przy użyciu argumentu odwołania:
void get(int, int&); void get(int, char&);
chociaż prawdopodobnie użyłbym szablonu lub funkcji o innych nazwach, takich jak twój drugi przykład.
źródło
int
kod błędu.Możesz myśleć w ten sposób:
Ty masz:
int get(int); char get(int);
Nie jest też obowiązkowe zbieranie wartości zwracanej przez funkcję podczas wywoływania.
Teraz wzywasz
get(10); -> there is an ambiguity here which function to invoke.
Tak więc nie ma znaczenia, jeśli przeciążanie jest dozwolone na podstawie zwracanego typu.
źródło
Wskrzeszenie starego wątku, ale widzę, że nikt nie wspomniał o przeciążaniu przez ref-kwalifikatory. Kwalifikatory ref to funkcja języka dodana w C ++ 11 i dopiero niedawno się na nią natknąłem - nie jest tak rozpowszechniona jak np. Kwalifikatory cv. Główną ideą jest rozróżnienie między dwoma przypadkami: kiedy funkcja składowa jest wywoływana na obiekcie rvalue i kiedy jest wywoływana na obiekcie lvalue. Możesz w zasadzie napisać coś takiego (nieznacznie modyfikuję kod OP):
#include <stdio.h> class My { public: int get(int) & { // notice & printf("returning int..\n"); return 42; } char get(int) && { // notice && printf("returning char..\n"); return 'x'; }; }; int main() { My oh_my; oh_my.get(13); // 'oh_my' is an lvalue My().get(13); // 'My()' is a temporary, i.e. an rvalue }
Ten kod wygeneruje następujące dane wyjściowe:
returning int.. returning char..
Oczywiście, tak jak w przypadku kwalifikatorów cv, obie funkcje mogłyby zwrócić ten sam typ, a przeciążanie nadal by się powiodło.
źródło
Jak wspomniano wcześniej, szablony są w tym przypadku przesadą, ale nadal jest to opcja, o której warto wspomnieć.
class My { public: template<typename T> T get(int); }; template<> int My::get<int>(int); template<> char My::get<char>(int);
źródło
Chociaż większość innych komentarzy dotyczących tego problemu jest poprawna technicznie, możesz skutecznie przeciążać zwracaną wartość, jeśli połączysz ją z przeciążeniem parametru wejściowego. Na przykład:
class My { public: int get(int); char get(unsigned int); };
PRÓBNY:
#include <stdio.h> class My { public: int get( int x) { return 'I'; }; char get(unsinged int x) { return 'C'; }; }; int main() { int i; My test; printf( "%c\n", test.get( i) ); printf( "%c\n", test.get((unsigned int) i) ); }
Wynikiem tego jest:
źródło
Nie ma możliwości przeciążenia przez zwracany typ w C ++. Bez użycia szablonów, za pomocą
get_int
iget_char
będzie to najlepsze co możesz zrobić.źródło
template <class T> T get(int)
mogłoby zadziałać?get<int>
lubget<char>
, co tak naprawdę nie daje ci wiele przewagiget_int
iget_char
jeśli nie używasz również innych funkcji szablonu.T
czy masz coś takiegoT get(T)
. Jeśli wywołaszget('a')
, kompilator wywnioskuje, żeT
jest to achar
i nie musisz jawnie wywoływaćget<char>('a')
. Nadal nie jestem pewien, czy to standard, chociaż myślę, że tak. FYI, zarówno GCC, jak i Clang to obsługują.T
wszystkich innych elementów, łącznie z typem zwracanym. Spodziewałem się, że podasz przykład kompilatora wnioskującegoT
dla funkcji w pierwszym komentarzu Niklasa.Nie można przeciążać metod opartych na typach zwracanych. Najlepszym rozwiązaniem jest utworzenie dwóch funkcji o nieco innej składni, na przykład w drugim fragmencie kodu.
źródło
nie możesz przeciążać funkcji w oparciu o zwracany typ funkcji. możesz przesadzić na podstawie typu i liczby argumentów, które przyjmuje ta funkcja.
źródło
Użyłem odpowiedzi Jamesa Kanze za pomocą proxy:
https://stackoverflow.com/a/9569120/262458
Chciałem uniknąć używania wielu brzydkich static_castów na void *, więc zrobiłem to:
#include <SDL_joystick.h> #include <SDL_gamecontroller.h> struct JoyDev { private: union { SDL_GameController* dev_gc = nullptr; SDL_Joystick* dev_js; }; public: operator SDL_GameController*&() { return dev_gc; } operator SDL_Joystick*&() { return dev_js; } SDL_GameController*& operator=(SDL_GameController* p) { dev_gc = p; return dev_gc; } SDL_Joystick*& operator=(SDL_Joystick* p) { dev_js = p; return dev_js; } }; struct JoyState { public: JoyDev dev; }; int main(int argc, char** argv) { JoyState js; js.dev = SDL_JoystickOpen(0); js.dev = SDL_GameControllerOpen(0); SDL_GameControllerRumble(js.dev, 0xFFFF, 0xFFFF, 300); return 0; }
Działa świetnie!
źródło