2021年9月25日

开发小记 C++跨文件编写导致的函数重复定义问题 2021 09 24

作者 TheWhiteDog9487

提示:本篇文章可能导致您血压急剧升高,请斟酌后再决定是否继续阅读

事情是这样的:
今天班会课老李(班主任)还是班长?忘了,反正说是需要一个点名机,随机抽同学的名字
我会编程所以我直接A了上去,把这事情给揽下来了,反正也不是多大点事,这个程序设计起来挺简单的,能用就行

回到家之后直接开干,VS2019冲就完了,直到我想测试一下函数,这个时候的文件结构大概长这样(我没有复制源文件,随便写了个例子,效果一样):

// 源1.cpp
#include <iostream>
#include <string>
using namespace std;
void func1() {
	cout << "测试函数启动" << endl;
}
// 源.cpp
#include "源1.cpp"
int main() {
	func1();
}

有没有觉得哪里不对劲?感觉都挺正常的,对吧?这些代码完完全全是合法的,没有违反哪怕一点规则。在生成可执行文件前VS半个错也不会报,连警告都没有,但是生成的时候直接会出现两个错误,就是这货:

猜猜是为什么?func1()的问题?main()的问题?还是iostream,string,std的问题?
都不是

你会发现把【源1.cpp】的代码原封不动地搬到一个【.h】头文件里然后【源.cpp】里的【include “源1.cpp”】修改一下,问题就解决了,一模一样的代码。

问题就出在这个引用上,先说结论:头文件才需要调包含,函数源文件不需要,并且在这种情况下也不能被包含

我们把代码修改一下,并且新增一个头文件

// 标头.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
void func2() {
	cout << "第二个测试函数启动" << endl;
}
// 源.cpp
#include <iostream>
#include <string>
#include "标头.h"
using namespace std;
int main() {
	func1();
	func2();
}
// 源1.cpp
#include <iostream>
#include <string>
using namespace std;
void func1() {
	cout << "测试函数启动" << endl;
}

这个时候你会发现【func2();】正在正常工作,但是【func1();】没有,报错是未定义的标识符
怎么办?修补程序给的解决方案是【#include “源1.cpp”】,因为它知道 【func1();】 的函数定义就在【 源1.cpp 】里面
但如果你就这么做了的话那可就上了贼船了,多重定义的报错肯定是还有你的份的

那有没有什么阳间的解决方案呢?有的,上面除【标头.h】外的代码都不需要动,只需要在【标头.h】中增加一个【void func1();】声明,完事(注意,在头文件内使用【#include “源1.cpp”】依然是不可行的)

这个问题其实困扰了我非常非常久,从最初开始就一直没找到问题原因
然而在这一次查错过程中我还发现了一些有意思的事,比如说:

  • 多个头文件和源文件都使用了【#include <iostream>】和【using namespace std 】这种语句,并且全部被含有main函数的源文件包含的时候,是不会报错的
  • 甚至你可以在一个头文件内包含自身,同样不会报错

这次其实差不多就是这么回事,但依然会存在一些问题,比如:
如果一个源文件内不包含函数只有类和变量,那是否仍然不需要调用include?

这个我就没有去测试了,但如果类和变量在源文件内需要被包含的话,那可能的解决方法就是再多开几个新文件,一个专门用来写变量一个专门用来写类,这就是之后的事情了