C++:Name Lookup & Best Match

名字查找

每当一个变量或者一个对象出现,编译器都会进行名字查找(name lookup),以确认这个变量或对象的具体属性。通常状况下,程序会从变量出现的地方开始向上查找,由内向外查找各级做用域直到全局做用域,找到同名的变量声明即中止,若最终没找到则报错。ios

#include <iostream>
using namespace std;

int a = 0;

int main() {
    string a = "1";
    cout << a << endl; // 在main函数体内找到了a的声明,中止名字查找,输出为string的内容“1”
    return 0;
}

名字查找还受到做用域限定符::的影响,若变量以前出现了做用域限定,那么则会从限定的做用域内进行全局搜索,而且不会查找其余位置。若是::以前没有出现做用域名,那么就会在全局做用域查找。函数

#include <iostream>
using namespace std;

int a = 0;

int main() {
    string a = "1";
    cout << ::a << endl; // 限定a的查找从全局做用域开始,那么首先被找到的是a的int类型定义,程序输出0
    return 0;
}

此外,因为在找到同名声明以后便会中止查找,函数匹配出如今名字查找以后spa

#include <iostream>
using namespace std;

void print() { cout << "1" << endl; }

int main() {
    int print;
    print(); // 试图调用print(),但程序没法经过编译,这是由于在找到int型变量print以后,
             // 编译器就中止了查找,把一个变量看成函数调用显然是错误的
    return 0;
}

名字隐藏

从上面的例子能够看出,在不使用访问限定符的状况下,内层做用域的变量会隐藏外层做用域的同名变量,即发生了名字隐藏。名字隐藏还会发生在类的继承过程,在子类定义和父类同名的成员时,会隐藏从父类继承来的成员,名字隐藏并非什么特性,相反,名字隐藏会增长程序编写的难度。咱们应该养成良好的命名习惯,避免出现名字隐藏code

最佳匹配

在函数调用时,首先对函数进行名字查找,在找到一个同名函数(假设不会出现命名冲突)时,编译器并不会中止查找,而是继续找出当前做用域的全部重载函数,而后根据最佳匹配规则,肯定实际调用的函数。不一样做用域的同名函数并不会被视为重载。最直观的例子是,类内的函数与类外的同名函数并不会造成重载。对象

在名字查找完成且不存在编译错误的状况下,编译器便开始肯定与调用匹配得最好的函数。最佳匹配原则也很简单,实参类型与形参类型越接近,匹配得越好。继承

void print(int a) { cout << "int" << endl; }

void print(double a) { cout << "double" << endl; }

print(1); // 1是int类型,与print的int形参重载构成最佳匹配,故程序输出“int”

但若是同时有多个函数与调用造成匹配,那么编译器将报错。编译器不容许有二义性的调用存在。作用域

void print(int a, int b, int c) { cout << "int" << endl; }

void print(double a, double b, double c) { cout << "double" << endl; }

print(1, 1.0, 1); // 编译器指出有多个函数重载匹配
相关文章
相关标签/搜索