题外话:==函数返回类型不参与函数重载,但仍然作为编译器构成函数签名的一部分==

实验文件:Math.cpp

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
void Log(const char* message);
int Multiply(int a, int b) {
Log("Multiply");
return a * b;
}
int main()
{
std::cout << Multiply(3, 5) << std::endl;
return 0;
}

此时Log(const char*)函数未定义。构建后当然会出现报错:

Math.obj : error LNK2019: 无法解析的外部符号 "void __cdecl Log(char const *)" ,函数 "int __cdecl Multiply(int,int)" 中引用了该符号

Step1

此时如果我们注释掉Multiply()中的Log()函数调用,文件就能正常构建。

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
void Log(const char* message);
int Multiply(int a, int b) {
//Log("Multiply");
return a * b;
}
int main()
{
std::cout << Multiply(3, 5) << std::endl;
return 0;
}

因为Multiply()不再调用Log()函数,自然不会在Multiply()中出现链接问题

Step2

现在只注释掉main()函数中对Multiply()函数的调用。直觉上似乎没错

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
void Log(const char* message);
int Multiply(int a, int b) {
Log("Multiply");
return a * b;
}
int main()
{
//std::cout << Multiply(3, 5) << std::endl;
return 0;
}

但结果还是报错了,同样的报错

Math.obj : error LNK2019: 无法解析的外部符号 "void __cdecl Log(char const *)" ,函数 "int __cdecl Multiply(int,int)" 中引用了该符号

问题还是Multiply()调用了Log()函数,虽然main()函数不再Multiply()函数,实际运行时看似不会有链接问题。但是,并不保证会有其它翻译单元是否会调用这里的Multiply()函数,所以还是会出现链接问题

Step3

注意到上面会出问题的关键是其它翻译单元,如果其它翻译单元无法调用Multiply()函数,这个问题似乎就能得到解决。也就是说,让Multiply()函数让其它翻译单元不可见即可。

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
void Log(const char* message);
static int Multiply(int a, int b) {
Log("Multiply");
return a * b;
}
int main()
{
//std::cout << Multiply(3, 5) << std::endl;
return 0;
}

这样就能成功构建,没人调用Multiply(),也就不会有链接问题。

  • 这里就体现了static关键字使函数让其它翻译单元不可见的能力