分离编译模式简介

http://blog.csdn.net/jiejinquanil/article/details/50984347

1、定义 
分离编译模式源于C语言,在C++语言中继续沿用。简单地说,分离编译模式是指:一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件连接起来形成单一的可执行文件的过程。

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

3、分离编译模式的的要点 
(1)每个函数或外部变量(全局变量)只能被定义一次,但可以被多次“声明”。见下面的程序:

#include <iostream>
using namespace std;
void func();
void func();
void func(){
         cout<<”This ia a demo”<<endl;
}
int main(){
         func();
}

函数func()被多次声明,并不影响程序的正常编译和运行。其实这正是C++分离编译模式的特点之一。在一个源文件中允许同时包含定义和声明同一个标识符的语句,这样就有利于头文件内容的组织。 
(2)函数声明也是有作用域的。 
类的成员函数只能在类体中声明。对于外部函数,如果是在一个函数体内声明另一个外部函数,那么该函数声明的作用域就是从声名处开始到函数体结束为止。在别的位置要调用这个函数,还必须再次声明。 
如下面的程序,由两个源文件组成,a.cpp和b.cpp。函数func()定义在a.cpp中,b.cpp中有两个函数show()和main()都调用了a.cpp中定义的函数func()。如果坚持将函数声明放在函数体内部,则在函数show()和main()中必须分别对函数func()进行声明,否则编译出错。程序如下:

/***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)一个函数被声明却从未定义,只要没有发生函数调用,编译连接是不会出错的。参考如下程序:

#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()有可能是在别的源文件中定义的。下面的程序就说明了这一点:

/****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是被“分离“实现的。所以,分离编译模式关心的是函数的调用规范(函数原型),至于函数是否真正实现要到连接的时候才能被发现。 
由分离编译模式也可以得到头文件的书写规范。头文件的目的是提供其他源文件中定义的,可以被当前源文件使用的内容(函数、变量等)的声明。因此,有个基本的假设是:头文件要被多次被不同的源文件包含。因此,一般都不在头文件中定义函数、定义外部变量,因为这样的头文件只能被包含一次,没有被包含第二次的可能性,背离了设立头文件的初衷。 
在一个源文件中定义函数,在另一个源文件中调用该函数,是分离编译模式下十分普遍的现象。但是如果定义的不是一个普通函数,而是一个函数模板,却可能发生错误。

时间: 2024-12-07 08:09:46

分离编译模式简介的相关文章

模板与分离编译模式

代码编译运行环境:VS2012+Debug+Win32 1.分离编译模式 一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件连接起来形成单一的可执行文件的过程成为分离编译模式. 2.使用模板在连接时出错 在C++程序设计中,在一个源文件中定义某个函数,然后在另一个源文件中使用该函数,这是一种非常普遍的做法.但是,如果定义和调用一个函数模板时也采用这种方式,会发生编译错误. 下面的程序由三个文件组成:func.h用来对函数模板进行申明,func.cpp用来

Java的MVC模式简介

Java的MVC模式简介 MVC(Model View Control)模型-视图-控制器 首先我们需要知道MVC模式并不是javaweb项目中独有的,MVC是一种软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller),即为MVC.它是一种软件设计的典范, 一.MVC与模板概念的理解 MVC本来是存在于Desktop程序中的,M是指数据模型,V是指用户界面,C则是控制器.使用MVC的目的是将M和V的实现代码分离,从而使同一个

c++编译过程简介

了解编译过程的益处 c++工程相关的问题 什么是库?静态库和动态库又有什么区别? 头文件起什么作用? 编译过程简介 名词: 编译:把源文件中的源代码翻译成机器语言,保存到目标文件中.如果编译通过,就会把CPP转换成OBJ文件. 编译单元: 每个cpp就是一个编译单元,每个编译单元相互之间是独立且相互不知的.一个编译单元(Translation Unit)是指一个.cpp文件以及这所include的所有.h文件,.h文件里面的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一

(转)c++模板函数声明定义分离编译错误详解

当我们声明和定义一个模板的时候,必须要让声明和定义放在一个文件里.否则编译器会报错. 这就是为什么boost的实现文件的后缀名是hpp了. 这其中的理由是什么呢?为什么会这样? 首先,一个编译单元(translation unit)是指一个.cpp文件以及它所#include的所有.h文件,.h文件里的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件(假定我们的平台是win32),后者拥有PE(Portable Executable,即windows可执行文

类模板的分离编译

一直觉得模板类是特别神奇的东西,它可以构造出不同类型的对象,使代码更加的灵活.这个过程就是类模板的实例化. 我们使用类的模板写一个stack类: #include<assert.h> #include"Seqlist1.h" using namespace std; template<class T,template<class> class Container  = Seqlist> class Stack { public: void Push(

c++ 模板 不能 分离编译

C++Template头文件和定义分开编译的问题 (1) // Foo.htemplate<typename T>class Foo{public:void f();}; // Foo.cpp#include <iostream>#include "Foo.h" template<typename T>void Foo<T>::f(){std::cout << "Foo<T>::f()/n";}

【C++】C++问题——类模板分离编译、函数对象、智能指针

C++类模板的分离编译 过去很多类模板都是整个类连同实现都放在一个头文件里,像STL库就是遵循这样的策略来实现类模板的.现在的标准正试图矫正这种局面. 在实现中又许多函数模板.这意味着每个函数都必须包含模板声明,并且在使用作用域操作符的时候,类的名称必须通过模板变量来实例化. 比如一个operator=的代码: template <typename Object> const MemoryCell <Object> & MemoryCell<Object>::o

分离编译

分离式编译是指一个完整的程序或项目由若干个源文件共同实现,每个源文件单独编译生成目标文件,最后将该项目中的所有目标文件连接成一个单一的可执行文件的过程. 每个.cpp源文件经过预处理,它所包含的.h文件的代码都会被展开到其中.再经过编译器的编译汇编等过程,将该.cpp文件转变为.obj文件,这是此文件已经变为二进制文件,本身包含的就是二进制代码.这时,该文件还不一定能够执行,因为并不保证其中一定有main函数,或者该源文件中的函数可能引用了另一个源文件中定义的某个变量或者函数调用,又或者在程序中

Release编译模式下,事件是否会引起内存泄漏问题初步研究

记:不常发生的事件内存泄漏现象 想必有些朋友可能也常常使用事件,但是很少解除事件挂钩程序也没有听说过内存泄漏之类的问题.幸运的是,在某些情况下,的确不会出问题,很多年前做的项目就跑得好好的,我们静态可以做一个实验来再次验证下.为了验证这个问题,我一度怀疑自己代码写错了,甚至照着书上(网上)例子写也无法重现事件引起内存泄漏的问题,难道教科书说错了么? 首先来看看我的代码,先准备2个类,一个发起事件,一个处理事件: class A { public event EventHandler ToDoSo