前端学C++

139 阅读2分钟

这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

函数重载

对于函数而言,不同的参数列表的同名函数即为重载行为:

void print(const char * str, int width); // #1 
void print(double d, int width); // #2 
void print(long l, int width); // #3 
void print(int i, int width); // #4 
void print(const char *str); // #5

print("Pancakes", 15); // 调用 #1 
print("Syrup"); // 调用 #5 
print(1999.0, 10); // 调用 #2 
print(1999, 12); // 调用 #4 
print(1999L, 15); // 调用 #3

注意函数重载的实现是依靠声明不同的参数列表,而非返回类型,函数重载的底层实现是由于编译器的如下操作:

long MyFunctionFoo(int, float);  \\你的函数声明
?MyFunctionFoo@@YAXH \\ 编译器干的

根据函数返回值、函数名、参数列表,编译器会进行一个称为name decorationname mangling的操作,生成一段hash一样的函数标识符(因而函数参数列表也被称为函数签名)。

函数模板

先来看看函数模板是怎么使用的。

template <typename T>
void Swap(T &a, T &b);

int main(){
    using namespace std;
    int i = 1;
    int j = 2;
    Swap(i,j);
    std::cout << i << ',' << j;
    double x = 1.0;
    double y = 2.0;
    Swap(x,y);
    std::cout << x << ',' << y;
}

template <typename T>
void Swap(T &a, T &b){
    T temp;
    temp = a;
    a = b;
    b = temp;
}

函数模板和函数重载都使编码更高效,一个避免了因为类型不同反复实现同样的逻辑,一个提供了更好的语义性。

编译器如何处理重载函数与函数模板

由于多个重载的函数、以及函数模板(甚至函数模板的重载)的存在,当一个函数被调用时,可能能够精确定位到某一个函数声明(Exact Match),但也可能出现能够定位到多个函数声明的情况,这时编译器会根据一些原则进行trivial conversion,找到一个最合适的函数,如果失败了,就报错,关于这种转换的优先度规则,就跟css优先级这种东西一样,死记没必要,用起来自然就懂了,这里甩个查阅的链接。