当前位置:  开发笔记 > 编程语言 > 正文

根据返回值重载C++函数

如何解决《根据返回值重载C++函数》经验,为你挑选了5个好方法。

我们都知道你可以根据参数重载一个函数:

int mul(int i, int j) { return i*j; }
std::string mul(char c, int n) { return std::string(n, c); } 

你能根据返回值重载一个函数吗?根据返回值的使用方式定义一个返回不同内容的函数:

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)

您可以假设第一个参数介于0-9之间,无需验证输入或进行任何错误处理.



1> paercebal..:

您必须告诉编译器使用哪个版本.在C++中,您可以通过三种方式完成.

通过键入明确区分呼叫

你有点作弊,因为你发送一个整数给一个等待char的函数,并且当'6'的char值不是6但是54(用ASCII)时错误地发送了数字6:

std::string mul(char c, int n) { return std::string(n, c); }

std::string s = mul(6, 3); // s = "666"

当然,正确的解决方案是

std::string s = mul(static_cast(54), 3); // s = "666"

我想,这是值得一提的,即使你不想要解决方案.

通过虚拟指针显式区分调用

您可以为每个函数添加一个伪参数,从而强制编译器选择正确的函数.最简单的方法是发送返回所需类型的NULL虚拟指针:

int mul(int *, int i, int j) { return i*j; }
std::string mul(std::string *, char c, int n) { return std::string(n, c); }

哪个可以与代码一起使用:

int n = mul((int *) NULL, 6, 3); // n = 18
std::string s = mul((std::string *) NULL, 54, 3); // s = "666"

通过模板化返回值来明确区分调用

使用此解决方案,我们创建一个"虚拟"函数,其代码在实例化时将无法编译:

template
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 i, int j)
{
   return i * j ;
}

template<>
std::string mul(int i, int j)
{
   return std::string(j, static_cast(i)) ;
}

因此,以下代码将编译:

int n = mul(6, 3); // n = 18
std::string s = mul(54, 3); // s = "666"

但是这个不会:

short n2 = mul(6, 3); // error: assignment of read-only variable ‘k’

通过模板化返回值明确区分调用,2

嘿,你也骗了!

是的,我确实对两个"重载"函数使用了相同的参数.但你确实开始作弊(见上文)......

^ _ ^

更严重的是,如果您需要具有不同的参数,那么您将编写更多代码,然后在调用函数时必须明确使用正确的类型以避免歧义:

// For "int, int" calls
template
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 i, int j)
{
   return i * j ;
}

// For "char, int" calls
template
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(char i, int j)
{
   return std::string(j, (char) i) ;
}

这段代码将被用作:

int n = mul(6, 3); // n = 18
std::string s = mul('6', 3); // s = "666"

并且以下行:

short n2 = mul(6, 3); // n = 18

仍然不会编译.

结论

我喜欢C++ ......

:-P



2> Coincoin..:
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;
};

不是我会用它.


您可以添加转换函数,如`operator identity :: type(){return&operator int; 允许将它传递给一个带有`int(*)()`的函数,如果调用了函数指针,则调用`operator int`函数.

3> Eclipse..:

如果你想mul成为一个真正的函数而不是一个类,你可以使用一个中间类:

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

这使您可以执行诸如将mul函数作为函数传递到std算法之类的操作:

int main(int argc, char* argv[])
{
    vector x;
    x.push_back(3);
    x.push_back(4);
    x.push_back(5);
    x.push_back(6);

    vector intDest(x.size());
    transform(x.begin(), x.end(), intDest.begin(), bind1st(ptr_fun(&mul), 5));
    // print 15 20 25 30
    for (vector::const_iterator i = intDest.begin(); i != intDest.end(); ++i)
        cout << *i << " ";
    cout << endl;

    vector stringDest(x.size());
    transform(x.begin(), x.end(), stringDest.begin(), bind1st(ptr_fun(&mul), 5));
    // print 555 5555 55555 555555
    for (vector::const_iterator i = stringDest.begin(); i != stringDest.end(); ++i)
        cout << *i << " ";
    cout << endl;

    return 0;
}



4> MrZebra..:

没有.

您不能通过返回值重载,因为调用者可以对其执行任何操作(或不执行任何操作).考虑:

mul(1, 2);

返回值刚被丢弃,因此无法单独根据返回值选择重载.


不,必须为可能的副作用做好工作.

5> Pieter..:

在类之间使用隐式转换.

class BadIdea
{
  public:
    operator string() { return "silly"; }
    operator int() { return 15; }
};

BadIdea mul(int, int)

你得到了这个想法,虽然很可怕.

推荐阅读
喜生-Da
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有