C++ (编译过程,C++与C和JAVA,模板)

本文详细介绍了C++的编译过程,包括预编译(宏展开、条件编译、头文件包含等)、编译(词法分析、语法分析等)、汇编和链接(静态链接与动态链接的区别)。此外,还讨论了C++与C和Java的区别,如异常处理、模板机制(包括模板特例化)以及引用和字符串类等特性。
摘要由CSDN通过智能技术生成

C++代码编译过程

1、预编译:主要处理源代码文件中的以“#”开头的预编译指令,处理规则如下(1)删除所有的#define,展开所有的宏定义,(2)处理所有的条件预编译指令比如#if,#endif, #ifdef, #elif和#else,(3)处理#include预编译指令,将文件内容替换到它的位置,这个过程是递归进行的因为头文件中包含其他文件,(4)删除所有的注释//和/**/,(5)保留所有的#pragma编译指令,比如#pragma once是为了防止有文件被重复引用,(6)添加行号和文件标识,便于编译时编译器产生调试用的行号信息和编译时产生的错误和警告。
2、编译:把预编译之后生成的xxx.i或.ii文件进行一系列词法分析,语法分析,语义分析和优化后,会生成相应的汇编代码文件。
3、汇编:将汇编代码转变成机器可以执行的指令(机器码文件),汇编器的汇编过程相对于编译器来说更简单,没有复杂的语法语义,也不用指令优化,只是根据汇编指令和机器指令的对照表一一翻译,汇编过程由汇编器as完成,汇编后产生目标文件(与可执行文件格式几乎一样)xxx.o(linux下),xxx.obj(window下)。
4、链接:将不同的源文件产生的目标文件进行链接,形成一个可执行的程序,链接分为动态链接和静态链接。静态链接中函数和数据被编译进一个二进制文件,在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把他们和应用程序的其他模块组合起来创建最终的可执行文件,这种方法优点就是运行速度快因为可执行程序中已经具备了所有执行程序所需要的东西,缺点就是每个可执行程序都需要一个目标文件的副本,所以会出现一个目标文件在内存中有多个副本的情况,并且当代码修改了要重新编译,更新比较困难。动态链接的基本思想是把程序按照模块拆分成各个相对独立的部分,在程序运行时才将它们链接在一起,不像静态链接那样把程序都链接成一个单独的可执行文件。有共享库,即使多个程序依赖同一个库,但是仍旧共享一个副本,并且更新方便,只用替换目标文件无需重新链接。但是会有性能损耗因为把链接推迟到了程序运行时,每次执行程序都要链接。
  动态链接需要和动态类型,动态绑定等相区分,静态类型是指对象在声明时采用的类型,在编译期确定;动态类型通常是指一个指针或者引用目前所指对象的类型,在运行期决定的;静态绑定绑定的是静态类型,所对应的函数或属性依赖于对象的静态类型,发生在编译期;动态绑定绑定的是动态类型,对应的函数或属性依赖于对象的动态类型发生在运行期。所以非虚函数一般都是静态绑定,虚函数都是动态绑定。
  零拷贝和对象复用:对象复用本质是一种设计模式“享元模式”,通过将对象存储到对象池中实现对象的重复利用,这样可以避免多次创建重复对象的开销,节约系统资源;零拷贝是一种避免CPU将数据从一块存储拷贝到另一块存储的技术,可以减少数据拷贝和共享总线操作的次数,比如C++中vector的一个成员函数emplace_back()体现零拷贝技术和push_back()一样可以将元素插入容器尾部,但是push_back()需要调用拷贝构造函数和转移构造函数,使用emplace_back()插入的元素原地构造,不需要触发拷贝构造和转移构造效率更高。

C++与其他语言的区别

1、标准C++中的字符串类取代了标准C函数库头文件中的字符数组处理函数(C中没有字符串类型),并且使用new和delete取代了malloc和free。
2、C++中用来做控制态输入输出的iostream类库替代了标准C中的stdio函数库。
3、C++中的try/catch/throw异常处理机制取代了标准C中的setjmp()和longjmp()函数。
4、C++可以重载C语言不行,就是运行有相同函数名但是参数类型不完全相同的。
5、C++允许变量在使用前的任何地方定义而C只能在函数的开头部分。
6、C++除了指针和值之外还增加了引用,引用型变量其实是其他变量的一个别名,可以认为是名字不同但是其他都相同。
7、新增了很多关键字比如bool, using, dynamic_cast,namespace等等。

C++与Java的区别:Java提高了较为简洁的语法,JVM可以安装到任何操作系统上,可移植性强。但是JAVA中没有指针的概念,而C++中的指针可以直接对内存进行操作,C++较为面向底层,速度更快,并且对windows开发非常友好可以直接编译生成.exe文件。并且C++编程对于语法要求更高,使用者语法基础相对要求也会更高,JAVA会让程序员把精力更放在程序设计本身,不需要时刻提醒自己忘写virtual或者delete等纯语法层面的东西。

模板

  模板定义很特殊。由template<…>处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。所以一般会在头文件中放置全部的模板声明和定义,下面是一个比较大小的模板示例:

#include<iostream> 
using namespace std; 
template<typename type1,typename type2>//函数模板 
type1 Max(type1 a,type2 b) { 
   return a > b ? a : b; 
} 
void main() { 
  cout<<"Max = "<<Max(5.5,4)<<endl; 
} 

  之后又引入了模板类,因为编写单一的模板,它能适应多种类型的需求,使每种类型都具有相同的功能,但对于某种特定类型,如果要实现其特有的功能,单一模板就无法做到,这时就需要模板特例化,模板特例化对单一模板提供的一个特殊实例,它将一个或多个模板参数绑定到特定的类型或值上一般分为模板函数特例化和类模板特例化。模板函数特例化必须为原函数模板的每个模板参数都提供实参,且使用关键字template后跟一个空尖括号对<>,表明将原模板的所有模板参数提供实参,举例如下:

template<typename T> //模板函数
int compare(const T &v1,const T &v2)
{
    if(v1 > v2) return -1;
    if(v2 > v1) return 1;
    return 0;
}
//模板特例化,满足针对字符串特定的比较,要提供所有实参,这里只有一个T
template<> 
int compare(const char* const &v1,const char* const &v2)
{
    return strcmp(p1,p2);
}

  特例化的本质是实例化一个模板,不是重载它,不会影响参数匹配,一般参数匹配都会以最佳匹配为原则,例如,此处如果是compare(3,5),则调用普通的模板,若为compare(“hi”,”haha”)则调用特例化版本。模板及其特例化版本应该声明在同一个头文件中,且所有同名模板的声明应该放在前面,后面放特例化版本。同样我们可以对类进行部分特例化。
参考资料:阿秀的学习笔记

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值