一个小问题,今天突然想不通了,关于头文件和源文件

mscorp 2008-12-11 10:57:58
一个类,在Sales_item.h文件里声明它,接着在Sales_item.cpp文件里实现它的定义,在里面包含了Sales_item.h文件
在另一个primer.cpp文件里的main函数中利用这个类实现功能。

一个问题:为什么我们在primer.cpp里包含的是Sales_item.h文件,而不是#include "Sales_item.cpp"呢?这样的话,编译器怎么知道成员函数的实现是在哪个文件的呢? Sales_item.h没有include Sales_item.cpp, primer.cpp里没有include Sales_item.cpp,编译器如何找着Sales_item.cpp的呢?

很愚蠢的个问题,以前不知道是没注意还是怎的,想当然的过去了,今天突然对这个想不通了!
...全文
538 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
yuanjq91 2011-05-14
  • 打赏
  • 举报
回复
也有这个疑惑 现在懂了。。
liangbch 2008-12-12
  • 打赏
  • 举报
回复
一般情况下,
1。函数声明,类型定义,全局变量声明,宏定义 是需要放在.h文件中的,这些内容可以被重复包含。
2. 函数的定义(实现),全局变量的定义,是需要放在.cpp文件中的,这些内容不可以被重复定义,否则在链接阶段,编译器就会发现了重复定义的符号而报错。

如果你能保证某个符号(全局变量或者函数定义),只出现一次,那么你完全可以将包含这个函数定义的cpp文件包含进来,为此,你需要做到2点。
1)那个cpp文件不能出现在project中
2)你仅仅可以#include这个cpp文件一次。

有些全局变量或者函数的定义是可以重复出现的,换句话说,你可以多次include 这个含有全局变量定义和函数实现的代码的文件(这个文件可以是.h文件,也可以是.cpp文件)
1)inline函数的实现
2)STL 函数的实现
3)const 类型的全局变量。
qq675927952 2008-12-12
  • 打赏
  • 举报
回复
up
fengogo 2008-12-12
  • 打赏
  • 举报
回复
这个问题一点都不愚蠢,相反是一个很好的问题。
但是我觉的大家回答的过于复杂, 我来个简单的.

为什么是include 头文件, 而不是include cpp 文件, 因为每个cpp文件是被编译器单独编译的(编译为目标文件), 为什么编译器知道要编译哪个cpp文件? 废话,因为你把cpp文件加入到了你的工程中.. 每一个cpp文件对应的目标文件再链接成可执行文件.
可以尝试一下, 如果你把原来的Sales_item.cpp 从工程中去掉,而在primer.cpp中 #include"Sales_item.cpp",
也许也能编译成功. 我没试过~
另外,我觉的跟预编译是有关系的, 因为include命令相当于把该文件复制粘贴到目标文件的开头.
mscorp 2008-12-12
  • 打赏
  • 举报
回复
这么多掌柜捧场 :)
mscorp 2008-12-12
  • 打赏
  • 举报
回复
嘿嘿,明白了!

非常感谢大家的热情回答!

lbh2001 2008-12-12
  • 打赏
  • 举报
回复
方便编译单元的独立编译,至于
如何引用外部符号这是连接器的工作


要分清楚编译和链接的过程就知道了
zhufeiguanghui 2008-12-12
  • 打赏
  • 举报
回复


这个问题不错啊!我想肯定和编译原理有关吧? 如果多多了解程序执行的各个环节,就会迎刃而解了
sagegz 2008-12-12
  • 打赏
  • 举报
回复
A good question!
Y神圣 2008-12-12
  • 打赏
  • 举报
回复
Mark
SearchLife 2008-12-12
  • 打赏
  • 举报
回复
楼上回答都不错啊,学习。
leboc 2008-12-12
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 wuyu637 的回复:]
这个问题一点都不愚蠢,相反是一个很好的问题。


===================================================
编译器编译的时候,实际上分了3个步骤,一个是预编译,和我们现在讨论的没有什么关系,然后第二是编译,就是把代码变成obj文件,第三个就是是链接,


在第二步的时候,编译器其实并不知道,这个在 SALES_ITEM.H里的申明的函数是在哪里实现的,不过只是通过#include这个头文件,知道有这么一个实现而已,
具体在哪…
[/Quote]
正解.主要是连接把所有相关的头文件都包含起来,同时编译器只允许包含包含一次,不然就重定义了.
speeder53 2008-12-12
  • 打赏
  • 举报
回复
mark
jackzhhuang 2008-12-12
  • 打赏
  • 举报
回复
实现文件里面包含了相应的头文件,编译后生成obj文件

obj文件是一个索引文件,通过它,就可以找到头文件和实现文件的联系

所以,包含一个头文件,就可以在连接的时候通过obj文件连接到实现文件,最终生成exe或者dll文件
wuyu637 2008-12-11
  • 打赏
  • 举报
回复
这个问题一点都不愚蠢,相反是一个很好的问题。


===================================================
编译器编译的时候,实际上分了3个步骤,一个是预编译,和我们现在讨论的没有什么关系,然后第二是编译,就是把代码变成obj文件,第三个就是是链接,


在第二步的时候,编译器其实并不知道,这个在 SALES_ITEM.H里的申明的函数是在哪里实现的,不过只是通过#include这个头文件,知道有这么一个实现而已,
具体在哪里实现,会在链接的时候去查找。


编译的过程,也就是第二步的时候,每个文件包含的函数的实现都会在编译器的一个表格里被登记起来,这样在第三步的时候,编译器就可以查找这个表格,找到
源文件里已经定义的函数,然后,进行链接。
如果在编译器的函数实现表格里没有这样的定义实现,那么,编译器可能去查找是否存在附加的Lib,或者dll文件,如果还是找不到,
就会报一个link error,
比如vc下就是
LNK2019
函数只有申明,没有实现时

unresolved external symbol 'symbol' referenced in function 'function'
lann64 2008-12-11
  • 打赏
  • 举报
回复
编译器编译primer.cpp时根本不需要知道知道Sales_item的实现代码,只需要知道它的类型定义就够了。
怎么把这些实现代码连接在一起是link程序的事,link根据入口地址进行连接。

建议看看linker and loader 这本书。
sys0006 2008-12-11
  • 打赏
  • 举报
回复
首先你的工程里有一个工程文件,VC是.dsp,VS2003以上是.vcproj,里面记录了你们工程有哪些文件
编译支持分开编译为obj文件,然后进行根据工程文件进行链接操作。
BluntBlade 2008-12-11
  • 打赏
  • 举报
回复
编译器只管把代码编译成目标码,链接器会解析函数调用并在目标码中查找函数入口地址。

65,211

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧