Fork me on GitHub

VS2022编译错误:链接器工具错误 LNK2005

产生原因

  自己在学习namespace时,参照C++ plus“9.3.2 新的命名空间特性”一书写了基本相同的代码,分别定义了h文件和两个CPP文件,其中一个CPP用来定义变量,一个CPP用来跑main(void)。文件代码如下:

head.h文件

#pragma once
#include<string>
#include <iostream>

namespace pers
{
	struct Person;
	inline void getPerson(struct Person& rp);//编译错误的时候没有inline
	inline  void showPerson(struct Person& rp);
}

namespace debts
{
	struct Debt;
	static void getDebt(struct Debt& rd);//编译错误的时候没有static
	static void showDebt(struct Debt& rd);
	static double sumDebts(const struct Debt ar[], int n);
}

source.cpp

#include "head.h"

namespace pers
{
	using namespace std;

	struct Person
	{
		std::string fname;
		std::string lname;
	};
	//拿取名字
	void getPerson(struct Person& rp)
	{
		cout << "Enter the first name: ";
		cin >> rp.fname;
		cout << "Enter the last name: ";
		cin >> rp.lname;
	}
	//展示名字
	void showPerson(struct Person& rp)
	{
		cout << rp.fname << rp.lname << endl;
	}
}


namespace debts
{
	using namespace pers;

	struct Debt
	{
		Person name;
		double amount;
	};

	void getDebt(struct Debt &rd)
	{
		getPerson(rd.name);//debt类型
		cout << "Enter debt: " << endl;
		cin >> rd.amount;//存放欠款
	}

	void showDebt(struct Debt& rd)
	{
		showPerson(rd.name);
		cout << rd.amount << endl;
	}

	double sumDebts(const struct Debt ar[], int n)
	{
		double total=0.0;
		for (int i = 0; i < n; i++)
			total+= ar[i].amount;
		return total;
	}
}

main.cpp

#include "source.cpp"
#include "head.h"

int main(void)
{
	using debts::Debt;
	using debts::showDebt;

	struct Debt user = {{"zhang","wei"},123};

	showDebt(user);
	return 0;
}

编译错误现象

解决过程

1、尝试将source.cpp文件改为.h文件,编译错误
2、尝试将main.cpp文件中的.h文件包含去除,避免二次包含,编译错误
3、迫不得已按照官方的处理办法进行了static,但个人感觉inline内联更好一点,至少占用的栈资源能少一点。链接器工具错误和警告 (LNKxxxx)

结论

  结合网络相关文章,我认采纳的错误原因函数产生了二义性。当同时,网上各种文章对此错误的原因分析分别为:

  • #ppragma once只能识别一次,第二次包含再遇到#program once就会判定错误(可能,但是个人仁伟既然有#pragma once用法,vs怎末可能第二次识别的时候错误了呢)
  • .h文件不能多次包含(实际因为#pragma once不会有这种情况)
  • .mian不能多处定义(不会有这种非常低级的错误)
  • 变量或函数多次定义(可能)
  • 强符号不能多次定义(又多了解了一点)

  当然,上面的说法可能大家实际需要的情况不一样,有道理但是并不适用于我的场景,我感觉比较合理的说法是:函数多次定义,应为函数首先在Scource文件中进行了定义,在h文件中进行了声明,但是在执行main文件时又包括了一次source文件,导致函数产生二义性,根本原因是函数的特征符相同,也就是编译器首先进行函数重载,但是发现特征符相同,所以报二次定义。
可以采用inline内联进行文本替换,当然依旧按值传递;也可以采用static声明内部链接性,允许每一个包含头文件的cpp文件创建该函数的副本。

 

posted @ 2022-10-03 14:18  张一默  阅读(505)  评论(0编辑  收藏  举报