提问cpp之编译单元

提问cpp之编译单元

  • 提问1:
  • 回答1:
    • 为什么模板都写在头文件里,写在.cpp文件会怎样?
    • 头文件中直接定义int a会有什么问题?
    • 为什么重复定义会出问题,这是谁判断的?
  • 提问2:
  • 回答2:
  • 错误再现(动图)

提问1:

问,为什么模板都写h头文件里面,非要写cpp文件会咋样?还有什么头文件直接int a会有啥问题,我说可能会重复定义,然后问我为啥重复定义就会出问题,这块是谁判断的?

回答1:

你提到的两个问题涉及到C++模板的使用习惯以及C/C++中全局变量定义的问题,下面我分别解释一下:

为什么模板都写在头文件里,写在.cpp文件会怎样?

C++模板是一种编程技术,允许程序员编写与类型无关的代码。当你使用模板定义一个函数或类时,编译器会根据你实际使用的类型生成具体的实现。这个过程叫做模板实例化。

  • 写在头文件(.h或.hpp)中:将模板定义在头文件中,意味着当这个头文件被包含到一个.cpp文件中时,模板的定义也被一起包含进来。这样,编译器在编译这个.cpp文件时,就可以看到模板定义并据此生成相应类型的实例化代码。这是必要的,因为C++标准规定,模板的实例化是在编译时进行的,而且必须在调用模板代码之前或者在模板定义所在的编译单元中完成。
  • 写在.cpp文件中:如果你把模板的定义只放在一个.cpp文件中,那么其他.cpp文件中的代码如果试图使用这个模板,编译器是看不到模板定义的,因为编译器是分别编译每个.cpp文件的。结果就是,编译器无法为这些外部使用的类型生成模板的实例,导致链接错误,因为在链接阶段,链接器找不到模板实例的具体实现。

头文件中直接定义int a会有什么问题?

在头文件中直接定义全局变量(如int a;)会引起多重定义的问题。这是因为当多个.cpp文件包含同一个头文件时,每个.cpp文件都会有一个a的定义。当这些.cpp文件被编译成对象文件后,链接器在尝试将它们链接成一个可执行文件时,会发现有多个a的定义,这违反了C/C++中关于一个程序内全局标识符(如变量、函数等)应有且只有一个定义的规则(One Definition Rule, ODR)。

为了解决这个问题,通常在头文件中使用extern关键字来声明全局变量而不是定义它。如extern int a;,然后在某一个.cpp文件中定义这个变量int a;。这样,a的定义只存在于一个地方,而其他文件通过包含头文件来引用a的声明,从而避免了多重定义的问题。

为什么重复定义会出问题,这是谁判断的?

关于为什么重复定义会出问题,这是由编译器和链接器共同决定的。编译器负责处理单个源文件,确保语法和语义的正确性。当多个源文件编译后需要合并成一个程序时,这个任务就交给了链接器。链接器发现同一个符号有多个定义时,就会报错,因为它无法确定应该使用哪一个定义,这可能导致程序行为的不确定性。

简而言之,重复定义的问题主要在链接阶段被链接器发现并报错。这背后的原理是为了保证程序的一致性和预期行为,防止因为变量或函数的重复定义导致的潜在冲突和错误。

提问2:

只有一个cpp文件还行,不会保错,cpp文件≥2时,当你把模板声明在头文件,把模板定义到1.cpp时,编译时2.cpp如果用到了该模板,他就不知道了模板咋定义的了,每个cpp都是单独编译的

回答2:

你的理解是正确的。如果你将模板的声明放在头文件中,而将具体的定义放在某个.cpp文件中,那么当其他.cpp文件通过包含那个头文件试图使用该模板时,会遇到问题。因为模板的具体实现(定义)对于这些其他的.cpp文件来说是不可见的,编译器在编译这些其他文件时不能实例化所需的模板,从而导致链接错误。
这是因为模板的实例化通常发生在编译期间,编译器需要看到模板的完整定义来生成针对特定类型的代码。当模板的定义仅存在于一个.cpp文件中时,其他.cpp文件中的代码尽管包含了模板的声明,但在编译时它们无法访问到模板定义,因此编译器无法生成这些模板的实例。
这也是为什么推荐将模板的定义放在头文件中,或者使用模板的显式实例化(explicit instantiation)和显式特化(explicit specialization)来避免这个问题的原因之一。通过在头文件中包含模板的完整定义,确保了每个包含该头文件的.cpp文件都能看到模板定义,从而允许编译器为需要的类型生成模板实例。
当然,如果你的项目只包含一个.cpp文件,这个问题就不存在了,因为模板的声明和定义都在同一个编译单元中,编译器能够找到并实例化所需的模板。所以,你完全理解了模板在多文件项目中的使用限制,以及为什么在实践中通常将模板定义放在头文件中的原因。

错误再现(动图)

待补充…

  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏过山河,踏过海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值