我们可以在基类中声明一个具有相同签名但返回类型不同的函数吗

Can we declare a function with the same signature but different return type in the base class?

本文关键字:返回类型 函数 一个 基类 声明 我们      更新时间:2023-10-16

这个问题可能看起来很傻,但我想问。。有没有什么方法可以在一个类中声明一个具有相同签名但不同返回类型的方法(如int fun(int(和float fun(int((,在创建对象的过程中,我们可以动态决定执行哪个函数!我有编译错误。。。有没有其他方法可以实现这个逻辑可以使用模板。。。

您可以始终将返回值作为模板。

template<typename T> T fun(int);
template<> float fun<float>(int);
template<> int fun<int>(int);

你能在运行时动态地决定调用哪个吗?编号

@DeadMG提出了基于模板的解决方案,但您可以简单地"调整"签名(可以说,这就是模板参数的作用(。

这个想法只是添加一个伪参数:

struct Foo
{
  float fun(float); // no name, it's a dummy
  int fun(int);     // no name, it's a dummy
};

然后执行:

int main() {
  Foo foo;
  std::cout << foo.fun(int()) << ", " << foo.fun(float());
}

这可以完全用作模板解决方案(即从模板方法调用(,但更容易提取:

  • 不那么冗长
  • 函数模板专用化应该在类之外定义(尽管VC++将接受类中的内联定义(

我更喜欢避免函数模板的专门化,一般来说,就像参数的专门化一样,选择正确重载/专门化的规则很棘手。

您可以(但不应该(使用重载转换运算符的代理类。

带有实际用例的长示例*

让我以Dot&交叉乘积符号:

[…]

点积和叉积都有运算符*的可能性。

假设一个基本矢量类型(仅用于演示(:

struct Vector {  
         float x,y,z;  
         Vector() {}  
         Vector (float x, float y, float z) : x(x), y(y), z(z) {}  
}; 

我们观察到点积是标量,叉积是向量。在C++中,我们可能会重载转换运算符:

struct VecMulRet {
public:
        operator Vector ()  const {
                return Vector (
                        lhs.y*rhs.z - lhs.z*rhs.y,
                        lhs.z*rhs.x - lhs.x*rhs.z,
                        lhs.x*rhs.y - lhs.y*rhs.x
                );
        }
        operator float () const {
                return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z;
        }
private:
        // make construction private and only allow operator* to create an instance
        Vector const lhs, rhs;
        VecMulRet (Vector const &lhs, Vector const &rhs)
        : lhs(lhs), rhs(rhs)
        {}
        friend VecMulRet operator * (Vector const &lhs, Vector const &rhs);
};

只允许运算符*使用结构VecMulRet,禁止复制VecMulRets(偏执狂优先(。

操作员*的定义如下:

VecMulRet operator * (Vector const &lhs, Vector const &rhs) {
        return VecMulRet (lhs, rhs);
}

瞧,我们可以写:

int main () {
        Vector a,b;
        float dot = a*b;
        Vector cross = a*b;
}

顺便说一句,这是1999年建立的神圣标准的祝福。

如果你进一步阅读该线程,你会发现一个基准测试,它证实了这不会带来性能损失。

演示的简短示例*

如果这太难理解的话,一个更为复杂的例子:

struct my_multi_ret {
    operator unsigned int() const { return 0xdeadbeef; }
    operator float()        const { return 42.f;       } 
};
my_multi_ret multi () {
    return my_multi_ret();
}
#include <iostream>
#include <iomanip>
int main () {
    unsigned int i = multi();
    float f = multi();
    std::cout << std::hex << i << ", " << f << std::endl;
}

*你可以,但不应该,因为这不符合最小惊喜的原则,因为这不是常见的做法。尽管如此,这还是很有趣的。