按返回类型重载

Sho*_*hoe 74 c++ overloading

我在这里读到了几个关于这个主题的问题,这个问题似乎让我感到困惑.我刚刚开始学习C++,我还没有学过模板或运算符重载等等.

现在有一种简单的重载方式

class My {
public:
    int get(int);
    char get(int);
}
Run Code Online (Sandbox Code Playgroud)

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

class My {
public:
    int get_int(int);
    char get_char(int);
}
Run Code Online (Sandbox Code Playgroud)

Luc*_*ore 94

不,没有.您不能基于返回类型重载方法.

重载分辨率考虑了功能签名.功能签名由以下部分组成:

  • 功能名称
  • CV-预选赛
  • 参数类型

这是引用:

1.3.11签名

有关参与重载决策的函数的信息(13.3):它的参数类型列表(8.3.5),如果函数是类成员,函数本身和类的cv限定符(如果有的话)其中声明了成员函数.[...]

选项:

1)更改方法名称:

class My {
public:
    int getInt(int);
    char getChar(int);
};
Run Code Online (Sandbox Code Playgroud)

2)输出参数:

class My {
public:
    void get(int, int&);
    void get(int, char&);
}
Run Code Online (Sandbox Code Playgroud)

3)模板......在这种情况下过度杀伤.

  • 请注意,基于返回类型不能重载的*reason*是C++允许您丢弃函数调用的值.因此,如果您只是调用`my.get(0);`编译器将无法决定执行哪一段代码. (39认同)
  • 您不能在返回类型上重载正常函数,但编译器将根据生成的类型在转换运算符之间进行选择; 你可以利用这个来创建一个代理,它有效地表现就像你在返回类型上重载一样. (17认同)
  • @benzado在这种情况下,它应该只在这种情况下抛出编译器错误,否则它应该像在*so*许多其他场景中那样推断出类型. (9认同)
  • @JeffPigarelli模板解决方案意味着成员模板:`My :: get <T>(int)`.它是一个有效的替代方案__if_ 1)你必须处理许多不同的类型,所有类型都使用相同的基本代码(例如`boost :: lexical_cast <T>(someStringValue)`,或者你必须能够从一些函数中调用这些函数其他模板(`myMy.get <T>(i)`,其中`T`是另一个模板的参数.否则,正如Luchian所说,它们是矫枉过正的. (2认同)
  • @benzado出于相同的理由`void foo(int x = 0){} void foo(double x = 0){}`应该被禁止。但是,事实并非如此。只有在编译器确实无法区分(`foo()`)的情况下,您才会得到错误 (2认同)

Jam*_*nze 74

这是可能的,但我不确定这是我为初学者推荐的技术.与其他情况一样,当您希望函数的选择取决于返回值的使用方式时,您可以使用代理; 首先定义像getChar和的函数getInt,然后是一个get()返回代理的泛型,如下所示:

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

根据需要将其扩展为多种类型.

  • +1,虽然是一个极端情况,转换运算符实际上是在返回类型上重载,并且可以利用它来获取有关所有地方的此功能. (9认同)
  • @MatthieuM.关于所有地方,但有关隐含转换的常见警告.你确实冒着引入本来不存在的含糊之处的风险.但是,在代理的情况下,我认为风险很小 - 除了您想要隐式转换的情况之外,您不会拥有代理类型的实例.另请注意,代理中的转换计为一个用户定义的转换.如果你需要`std :: string`,而代理只提供`operator char const*()`,它就不会起作用. (3认同)

Mik*_*our 8

不,你不能通过返回类型重载; 仅通过参数类型和const/volatile限定符.

一种替代方法是使用引用参数"返回":

void get(int, int&);
void get(int, char&);
Run Code Online (Sandbox Code Playgroud)

虽然我可能会使用模板,或者像第二个例子那样使用不同名称的函数.

  • 请注意,char 和 int 类型可以隐式转换。 (2认同)

Who*_*ami 5

您可以这样想:

你有:

  int get(int);
  char get(int);
Run Code Online (Sandbox Code Playgroud)

并且,在调用时不强制收集函数的返回值。

现在,您调用

  get(10);  -> there is an ambiguity here which function to invoke. 
Run Code Online (Sandbox Code Playgroud)

因此,如果根据返回类型允许重载,则没有意义。


Mil*_*kic 5

复活一个旧线程,但我可以看到没有人提到引用限定符的重载。引用限定符是 C++11 中添加的语言功能,我最近才偶然发现它 - 它不像 cv 限定符那样广泛。主要思想是区分两种情况:在右值对象上调用成员函数时,以及在左值对象上调用成员函数时。你基本上可以写这样的东西(我稍微修改了 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
}
Run Code Online (Sandbox Code Playgroud)

此代码将产生以下输出:

returning int..
returning char..
Run Code Online (Sandbox Code Playgroud)

当然,与 cv 限定符的情况一样,两个函数都可以返回相同的类型并且重载仍然会成功。

  • 对于上下文,这里实际发生的是隐藏的“this”参数上的正常函数重载(“this&amp;”与“this&amp;&amp;”)。 (2认同)

yel*_*w01 5

如前所述,在这种情况下,模板有点矫枉过正,但它仍然是一个值得一提的选项。

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

template<> int My::get<int>(int);
template<> char My::get<char>(int);
Run Code Online (Sandbox Code Playgroud)