Przeciążenie funkcji C++ zgodnie z wartością zwracaną
Wszyscy wiemy, że można przeciążać funkcję zgodnie z parametrami:
int mul(int i, int j) { return i*j; }
std::string mul(char c, int n) { return std::string(n, c); }
Czy można przeciążać funkcję zgodnie z wartością zwracaną? Zdefiniuj funkcję, która zwraca różne rzeczy zgodnie z tym, jak używana jest zwracana wartość:
int n = mul(6, 3); // n = 18
std::string s = mul(6, 3); // s = "666"
// Note that both invocations take the exact same parameters (same types)
Można założyć, że pierwszy parametr mieści się w przedziale 0-9, nie ma potrzeby weryfikacji danych wejściowych ani obsługi błędów.
17 answers
class mul
{
public:
mul(int p1, int p2)
{
param1 = p1;
param2 = p2;
}
operator int ()
{
return param1 * param2;
}
operator std::string ()
{
return std::string(param2, param1 + '0');
}
private:
int param1;
int param2;
};
Nie żebym tego używał.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-05 08:50:53
Musisz powiedzieć kompilatorowi, której wersji użyć. W C++ można to zrobić na trzy sposoby.
Jawnie różnicuj wywołania wpisując
Trochę oszukałeś, ponieważ wysłałeś liczbę całkowitą do funkcji oczekującej na znak i błędnie wysłałeś liczbę 6, Gdy wartość znaku ' 6 ' nie jest 6, ale 54 (W ASCII):
std::string mul(char c, int n) { return std::string(n, c); }
std::string s = mul(6, 3); // s = "666"
Właściwym rozwiązaniem byłoby, oczywiście,
std::string s = mul(static_cast<char>(54), 3); // s = "666"
To było warte wspomnienia, myślę, nawet jeśli nie chcesz rozwiązanie.
Jawnie różnicuj wywołania za pomocą atrapy wskaźnika
Możesz dodać atrapę do każdej funkcji, zmuszając kompilator do wyboru właściwych funkcji. Najprostszym sposobem jest wysłanie atramentowego wskaźnika null typu pożądanego dla powrotu:
int mul(int *, int i, int j) { return i*j; }
std::string mul(std::string *, char c, int n) { return std::string(n, c); }
, który może być użyty z kodem:
int n = mul((int *) NULL, 6, 3); // n = 18
std::string s = mul((std::string *) NULL, 54, 3); // s = "666"
Jawnie różnicuj wywołania przez szablon zwracanej wartości
Dzięki temu rozwiązaniu tworzymy funkcję" atrapa " z kodem, który nie skompiluje się, jeśli utworzono instancję:
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
Zauważ, że ta funkcja nie będzie się kompilować, co jest dobrą rzeczą, ponieważ chcemy używać tylko niektórych ograniczonych funkcji poprzez specjalizację szablonu:
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
template<>
std::string mul<std::string>(int i, int j)
{
return std::string(j, static_cast<char>(i)) ;
}
W ten sposób skompiluje się następujący kod:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>(54, 3); // s = "666"
Ale ten nie:
short n2 = mul<short>(6, 3); // error: assignment of read-only variable ‘k’
Jawnie różnicuj wywołania przez szablon zwracanej wartości, 2
Hej, ty też oszukiwałeś!
Racja, użyłem tego samego parametry dla dwóch funkcji "przeciążonych". Ale zacząłeś oszukiwać(patrz wyżej)...
^_^
Mówiąc bardziej poważnie, jeśli potrzebujesz mieć różne parametry, będziesz musiał napisać więcej kodu, a następnie będziesz musiał jawnie używać właściwych typów podczas wywoływania funkcji, aby uniknąć niejednoznaczności:
// For "int, int" calls
template<typename T>
T mul(int i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
int mul<int>(int i, int j)
{
return i * j ;
}
// For "char, int" calls
template<typename T>
T mul(char i, int j)
{
// If you get a compile error, it's because you did not use
// one of the authorized template specializations
const int k = 25 ; k = 36 ;
}
template<>
std::string mul<std::string>(char i, int j)
{
return std::string(j, (char) i) ;
}
I ten kod będzie używany jako taki:
int n = mul<int>(6, 3); // n = 18
std::string s = mul<std::string>('6', 3); // s = "666"
I następujący wiersz:
short n2 = mul<short>(6, 3); // n = 18
Nadal nie kompiluje.
Podsumowanie
I kocham C++...
:-P
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-17 01:51:32
Jeśli chcesz, aby mul
było rzeczywistą funkcją zamiast klasą, możesz użyć klasy pośredniej:
class StringOrInt
{
public:
StringOrInt(int p1, int p2)
{
param1 = p1;
param2 = p2;
}
operator int ()
{
return param1 * param2;
}
operator std::string ()
{
return std::string(param2, param1 + '0');
}
private:
int param1;
int param2;
};
StringOrInt mul(int p1, int p2)
{
return StringOrInt(p1, p2);
}
To pozwala robić rzeczy takie jak przekazywanie mul
jako funkcji do algorytmów std:
int main(int argc, char* argv[])
{
vector<int> x;
x.push_back(3);
x.push_back(4);
x.push_back(5);
x.push_back(6);
vector<int> intDest(x.size());
transform(x.begin(), x.end(), intDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 15 20 25 30
for (vector<int>::const_iterator i = intDest.begin(); i != intDest.end(); ++i)
cout << *i << " ";
cout << endl;
vector<string> stringDest(x.size());
transform(x.begin(), x.end(), stringDest.begin(), bind1st(ptr_fun(&mul), 5));
// print 555 5555 55555 555555
for (vector<string>::const_iterator i = stringDest.begin(); i != stringDest.end(); ++i)
cout << *i << " ";
cout << endl;
return 0;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-09 21:02:03
Nie.
Nie można przeciążać wartością zwracaną, ponieważ wywołujący może z nią zrobić wszystko (lub nic). Consider:
mul(1, 2);
Wartość zwracana jest po prostu odrzucana, więc nie ma możliwości wyboru przeciążenia na podstawie samej wartości zwracanej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:05:46
Użyj niejawnej konwersji w klasie in between.
class BadIdea
{
public:
operator string() { return "silly"; }
operator int() { return 15; }
};
BadIdea mul(int, int)
Masz pomysł, okropny pomysł.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:13:31
Niech mul będzie klasą, mul (x, y) jej konstruktorem i przeciąży niektóre operatory odlewnicze.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:19:32
Nie można przeciążać funkcji tylko na podstawie zwracanej wartości.
Jednakże, podczas gdy ściśle mówiąc nie jest to funkcja przeciążona, możesz zwrócić ze swojej funkcji instancję klasy, która przeciąża operatory konwersji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:06:17
Zakładam, że możesz zwrócić jakiś dziwny typ Foo, który przechwytuje parametry, a następnie Foo ma implicit Operator int i operator string, i to "zadziała", choć tak naprawdę nie byłoby przeciążenia, a raczej ukrytą sztuczkę konwersji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:15:11
Hmmm, poniższy artykuł code project wydaje się robić to, czego szukasz. Must be magic;)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:13:15
Krótko i prosto, odpowiedź brzmi nie. W C++ wymagania są następujące:
1: Nazwa funkcji musi być taka sama
2: zbiór argumentów musi się różnić
* Typ powrotu może być taki sam lub inny
//This is not valid
int foo();
float foo();
typedef int Int;
int foo(int j);
int foo(Int j);
//Valid:
int foo(int j);
char* foo(char * s);
int foo(int j, int k);
float foo(int j, float k);
float foo(float j, float k);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-20 20:36:41
Z tego co wiem, to nie możesz (wielka szkoda...). Jako obejście można zamiast tego zdefiniować parametr " out " i przeciążyć go.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:04:32
Nie w C++. W powyższym przykładzie otrzymałbyś zwracaną wartość, która jest int rzuconym w coś, co string
może zrozumieć, najprawdopodobniej char
. Czyli ASCII 18 lub "device control 2".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:08:33
Możesz użyć powyższego rozwiązania functora. C++ nie obsługuje tego dla funkcji z wyjątkiem const. Możesz przeciążać na podstawie const.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:48:56
Możesz użyć szablonu, ale wtedy będziesz musiał podać parametr szablonu podczas wykonywania połączenia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:05:59
Umieścić go w innej przestrzeni nazw? Tak bym to zrobił. Nie jest to stricte przeciążenie, raczej posiadanie dwóch metod o tej samej nazwie, ale o innym zakresie (stąd operator:: Scope resolution).
Więc stringnamespace::mul i intnamespace:: mul. Może to nie jest to, o co prosisz, ale wydaje się, że to jedyny sposób, aby to zrobić.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:06:09
Mógłbyś zrobić coś takiego
template<typename T>
T mul(int i,int j){
return i * j;
}
template<>
std::string mul(int i,int j){
return std::string(j,i);
}
A potem nazwij to tak:
int x = mul<int>(2,3);
std::string s = mul<std::string>(2,3);
Nie ma możliwości przeciążenia wartości zwracanej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-22 15:11:05
OK geniusze;) tak to robicie jak zawodowcy.
class mul
{
int m_i,m_j;
public:
mull(int i,int j):m_i(i),m_j(j){}
template
operator R()
{
return (R)m_i * m_j;
}
};
Użyj jak
double d = mul(1,2);
long l = mul(1,2);
No stupid
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-14 05:05:37