[C++] 函数重载

函数重载

如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载函数。

void print(const char *cp);
void print(const int *beg, const int *end);
void print(const int ia[], size_t size);

int j[2] = {0,1};
print("Hello World!");
print(j, end(j) - begin(j));
print(begin(j), end(j));

main函数不能重载

对于重载函数来说,它们应该在形参数量或形参类型上有所不同。

不允许两个函数除了返回类型外其他所有的要素都相同。

有时候两个形参列表看起来不一样,实际上是相同的

int calc(const int &a);
int calc(const int&);

形参名只是起到了帮助记忆的作用。有没有它并不影响形参列表的内容

重载和const形参

顶层const不影响传入函数的对象。一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开

Record lookup(Phone);
Record lookup(const Phone);
// const Phone为顶层const、
Record lookup(Phone*);
Record lookup(Phone* const);
// Phone* const为顶层const

以上函数存在重复声明

如果形参是某种类型的指针或引用,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载,此时const是底层的

Record lookup(Account&);
// 函数作用域Account的引用
Record lookup(const Account&);
// 函数作用于常量引用
Record lookup(Account*);
// 作用于指向Account指针
Record lookup(const Account*);
// 作用于指向常量的指针

我们只能把const对象传递给const形参

相反的,非常量可以转换成const

所以以上4个函数都能作用于非常量对象或者指向非常量对象的指针。

当我们传递一个非常量对象或者指向非常量对象的指针使,编译器会优先选用非常量版本的函数

const_cast和重载

比较两个string对象的长度,并返回较短的那个引用

const string &shorterString(const string &s1, const string &s2)
{
    return s1.size() < s2.size() ? s1 : s2;
}

我们可以对两个非常量的string实参调用这个函数,但返回的结果是const string的引用。

所以我们需要一个新的函数,当实参不是常量时,得到的结果是一个普通的引用。可以使用const_cast完成。

string &shorterString(string &s1, string &s2) 
{
    auto &r = shorterString(const_cast<const string>(s1), const_cast<const string>(s2));
    return const_cast<string&>(r);
}

首先将实参强制转换成对const的引用,然后调用shorterString的const版本,const版本返回对const string的引用,然后将其转换成一个普通的string&。

重载与作用域

一般来说,将函数声明置于局部作用域内不是一个明智的选择。

重载对作用域的一般性质并没有改变,如果我们在内层作用域中声明名字,它将隐藏外层作用域中声明的同名实体。在不同作用域中无法重载函数名

在作用域中调用函数时,编译器首先寻找对该函数名的声明,一旦在该作用域内找到所需名字,编译器会自动忽略外层作用域中的同名实体。剩下来就是检查函数调用是否有效了。

在C++中,名字查找在类型检查之前

string read();
void print(const string &);
void print(double);
void fooBar(int ival)
{
    bool read = false;
    // 新作用域,隐藏了外层read函数
    string s = read();
    // 错误,read是bool类型变量
    void print(int);
    // 在作用域内声明函数
    print("Value: ");
    // 错误,作用域内只有print(int),外层print被隐藏
    print(ival);
    // 正确,调用当前print(int)
    print(3.14);
    // 正确,调用当前print(int).
}
void print(const string &);
void print(double);
void print(int);
void fooBar2(int ival) 
{
    print("Value: ");
    // 重载调用
    print(ival);
    // 重载调用
    print(3.14);
    // 重载调用,void print(double)
}
void print(const string &);
void print(double);
void print(int);
void fooBar2(int ival) 
{
    print("Value: ");
    // 重载调用
    print(ival);
    // 重载调用
    print(3.14);
    // 重载调用,void print(double)
}

 

posted @ 2017-12-23 16:02  immjc  阅读(304)  评论(0编辑  收藏  举报