C++分离式编译模式

1.分离编译模式的定义

编辑
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件连接起来形成单一的可执行文件的过程。 [1]  

2.分离编译模式的由来

编辑
分离编译模式是C/C++组织源代码和生成可执行文件的方式。在实际开发大型项目的时候,不可能把所有的源程序都放在一个头文件中,而是分别由不同的程序员开发不同的模块,再将这些模块汇总成为最终的可执行程序。
这里就涉及到不同的模块(源文件)定义的函数和变量之间的相互调用问题。C/C++语言所采用的方法是:只要给出函数原型(或外部变量声明),就可以在本源文件中使用该函数(或变量)。每个源文件都是独立的编译单元,在当前源文件中使用但未在此定义的变量或者函数,就假设在其他的源文件中定义好了。每个源文件生成独立的目标文件(obj文件),然后通过连接(Linking)将目标文件组成最终的可执行文件。
程序编译的简要过程包括 预处理(Preprocessing)、 编译(Compilation)、 汇编(Assembly)和 连接(Linking)。

3.分离编译模式的的要点

编辑
理解分离编译模式要注意以下几点。
(1 )每个函数或外部变量(全局变量)只能被定义一次,但可以被多次“声明”。见下面的程序[1]  
1
2
3
4
5
6
7
8
9
10
#include <iostream>
using  namespace  std;
void  func();
void  func();
void  func(){
          cout<<”This ia a demo”<<endl;
}
int  main(){
          func();
}
函数func()被多次声明,并不影响程序的正常编译和运行。其实这正是C++分离编译模式的特点之一。在一个源文件中允许同时包含定义和声明同一个标识符的语句,这样就有利于头文件内容的组织。
(2 )函数声明也是有作用域的。[1] 
类的成员函数只能在类体中声明。对于外部函数,如果是在一个函数体内声明另一个外部函数,那么该函数声明的作用域就是从声名处开始到函数体结束为止。在别的位置要调用这个函数,还必须再次声明。
如下面的程序,由两个源文件组成,a.cpp和b.cpp。函数func()定义在a.cpp中,b.cpp中有两个函数show()和main()都调用了a.cpp中定义的函数func()。如果坚持将函数声明放在函数体内部,则在函数show()和main()中必须分别对函数func()进行声明,否则编译出错。程序如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/***a.cpp***/
#include <iostream>
Using  namespace  std;
void  func(){
          cout<<”This is a demo”<<endl;
}
/***end of a.cpp***/
  
/****b.cpp****/
void  show(){
void  func();  //func()的声明必不可少
     func();
}
int  mian(){
          void  func();  // func()的声明必不可少
          func();
          show();
}
/****end of b.cpp****/
通常情况下,将外部函数或外部变量的声明放在.h头文件中。对于不在源文件中定义的函数(或变量),只要将相应的头文件通过#include指令包含进来,就可以正常使用了。
(3 )一个函数被声明却从未定义,只要没有发生函数调用,编译连接是不会出错的。[1] 
参考如下程序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using  namespace  std;
class  Demo{
public :
          void  func1();
          void  func2();
};
void  Demo::func1(){
          cout<<”This is a demo”<<endl;
}
int  main(){
          Demo obj;
obj.func1();
}              
观察以上程序可以,类Demo的定义是不完整的,因为成员函数func2未完成定义,但是func2从未发生过调用,所以,函数只有生命没有定义在不发生函数调用的情况下是可以通过编译连接的。
从分离编译模式的角度来看,函数Demo::func2()有可能是在别的源文件中定义的。下面的程序就说明了这一点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/****a.cpp****/    
#include <iostream>
using  namespace  std;
class  Demo{
public :
      void  func1();
      void  func2();
};
void  Demo::func2(){
      cout<<”This is func2”<<endl;
}       
/****end of a.cpp****/ 
  
/****b.cpp****/    
#include <iostream>
using  namespace  std;
class  Demo{
public :
      void  func1();
      void  func2();
};
void  Demo::func1(){
      cout<<”This is func1”<<endl;
}
int  main(){
     Demo obj;
     obj.func2();
}
/****end of b.cpp****/ 
观察以上程序,类Demo有两个成员函数,它们分别在a.cpp和b.cpp源文件中实现。类Demo是被“分离“实现的。所以,分离编译模式关心的是函数的调用规范(函数原型),至于函数是否真正实现要到连接的时候才能被发现。
由分离编译模式也可以得到头文件的书写规范。头文件的目的是提供其他源文件中定义的,可以被当前源文件使用的内容(函数、变量等)的声明。因此,有个基本的假设是:头文件要被多次被不同的源文件包含。因此,一般都不在头文件中定义函数、定义外部变量,因为这样的头文件只能被包含一次,没有被包含第二次的可能性,背离了设立头文件的初衷。
在一个源文件中定义函数,在另一个源文件中调用该函数,是分离编译模式下十分普遍的现象。但是如果定义的不是一个普通函数,而是一个函数模板,却可能发生错误。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值