按返回类型重载

我在这里读到一些关于这个主题的问题,这个问题对我来说似乎很困惑。我刚刚开始学习 C + + ,还没有研究过模板或者运算符重载之类的东西。

现在有没有一种简单的方法

class My {
public:
int get(int);
char get(int);
}

没有模板或者奇怪的行为? 或者我应该

class My {
public:
int get_int(int);
char get_char(int);
}

98234 次浏览

No there isn't. You can't overload methods based on return type.

Overload resolution takes into account the function signature. A function signature is made up of:

  • function name
  • cv-qualifiers
  • parameter types

And here's the quote:

1.3.11 signature

the information about a function that participates in overload resolution (13.3): its parameter-type-list (8.3.5) and, if the function is a class member, the cv-qualifiers (if any) on the function itself and the class in which the member function is declared. [...]

Options:

1) change the method name:

class My {
public:
int getInt(int);
char getChar(int);
};

2) out parameter:

class My {
public:
void get(int, int&);
void get(int, char&);
}

3) templates... overkill in this case.

There is no way to overload by return type in C++. Without using templates, using get_int and get_char will be the best you can do.

No, you can't overload by return type; only by parameter types, and const/volatile qualifiers.

One alternative would be to "return" using a reference argument:

void get(int, int&);
void get(int, char&);

although I would probably either use a template, or differently-named functions like your second example.

You can't overload methods based on return types. Your best bet is to create two functions with slightly different syntax, such as in your second code snippet.

you can't overload a function based on the return type of the function. you can overlead based on the type and number of arguments that this function takes.

It's possible, but I'm not sure that it's a technique I'd recommend for beginners. As in other cases, when you want the choice of functions to depend on how the return value is used, you use a proxy; first define functions like getChar and getInt, then a generic get() which returns a Proxy like this:

class Proxy
{
My const* myOwner;
public:
Proxy( My const* owner ) : myOwner( owner ) {}
operator int() const
{
return myOwner->getInt();
}
operator char() const
{
return myOwner->getChar();
}
};

Extend it to as many types as you need.

You can think this way:

You have:

  int get(int);
char get(int);

And, it is not mandatory to collect the return value of the function while invoking.

Now, You invoke

  get(10);  -> there is an ambiguity here which function to invoke.

So, No meaning if overloading is allowed based on the return type.

While most of the other comments on this problem are technically correct, you can effectively overload the return value if you combine it with overloading input parameter. For example:

class My {
public:
int  get(int);
char get(unsigned int);
};

DEMO:

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

The resulting out of this is:

I
C

Resurrecting an old thread, but I can see that nobody mentioned overloading by ref-qualifiers. Ref-qualifiers are a language feature added in C++11 and I only recently stumbled upon it - it's not so widespread as e.g. cv-qualifiers. The main idea is to distinguish between the two cases: when the member function is called on an rvalue object, and when is called on an lvalue object. You can basically write something like this (I am slightly modifying OP's code):

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

This code will produce the following output:

returning int..
returning char..

Of course, as is the case with cv-qualifiers, both function could have returned the same type and overloading would still be successful.

I used James Kanze's answer using a proxy:

https://stackoverflow.com/a/9569120/262458

I wanted to avoid using lots of ugly static_casts on a void*, so I did this:

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

Works perfectly!

As stated before, templates are overkill in this case, but it is still an option worth mentioning.

class My {
public:
template<typename T> T get(int);
};


template<> int My::get<int>(int);
template<> char My::get<char>(int);