c++ 编译期与运行期总结

分享到


百度分享

转自:http://hi.baidu.com/zhaoyong200518/item/8516dc59a65be1968d12edff

c++ 编译期与运行期总结

一 见识编译期的力量

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

#include "stdafx.h"

#include <iostream>

using
namespace std;

class
A{

public:

    virtual
void f(){ cout << "A"
<< endl; }

};

class
B :public
A

{

private:

    void
f(){ cout << "B"
<< endl; }

};

int
_tmain(int
argc, _TCHAR* argv[])

{

    A *pA = new
B();

    pA->f();

    

    

    return
0;

}

出现了很有趣的结果,在main函数中,访问到了B类中的私有方法。为什么会出现这样的结果呢?

一般来说外部对象访问类的私有成员,除非是友元,否则在编译的时候就会报错,但是上面那段代码却可以正常的编译通过。

C++因为支持面向对象编程,制订了一系列实现策略的语言机制。其中,各种各样的“限制”主要是出现在编译时:因此如果直接B d;
d.f(); 就会导致编译错误:编译器发现

B::f()是B类的私有成员函数,因此拒绝这样的访问。

这里我们可以区分类和对象:类是编译期的概念,也是“访问权限”、“成员数据”、“成员函数”这几个概念的“作用域”。而对象的作用域是运行期。它包括类的实例、引用和指针。

A    *pA    =   
new    B();      这里   
pA    是一个    A* , 所以就作为一个A类的指针参与了编译;

因此从pA调用f()在编译器眼中,就是调用了A类的公开成员函数f()因此通过编译;然后在运行时,由于多态作用pA调用的f()是派生类的f()成员函数。

虽然这时f()是private成员函数,但是由于    private/public   
这些访问控制是编译时的限制,在运行时无效,所以B::f() 被成功调用。

如果能够理解这两个在不同时间作用的概念,这个问题就很好理解.

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lusure/archive/2009/12/31/5113217.aspx

2 上面的例子是转载的,里面有个例子是输出调试信息的,

1)

const bool g_debug=1

void Log(char* str) {

if (g_debug){

printf(str);

}

}

2) #define DEBUG

#ifdef DEBUG

#define LOG(m) \

{\

printf(m);

\ }\

#else

#define LOG(m)

#endif

有经验的程序员肯定一眼就看出来第二种Log输出方式比较好。第一种的判断是在运行期,而第二种的判断是在编译期。第一种在每次运行log函数的时候都会去判断全局变量,

而第二种是在编译的时候就已经将不需要的Log信息定义为空。因为编译消耗的时间是一次性的,而运行的效率是直接呈现给用户的。由这种节约时间的方法,

我们可以发现把很多函数的判断和计算放在编译期,会大大节约运行的时间,提供运行效率,但是编译器并不是万能,所以编译期能做的工作还是十分的有限。

二 编译期 运行期 说明

1. 编译期是指把你的源程序交给编译器编译的过程,最终目的是得到obj文件,链接后生成可执行文件。
运行期指的是你将可执行文件交给操作系统(输入文件名,回车)执行、直到程序执行结束的期

执行的目的是为了实现程序的功能 2. 编译期分配内存,就是用静态或全局数组。这是在编译的时候确定的。

编译期内存错误,就是比如某个数据段DATA段或者CODE段等等,超过跑这个程序的目标机的存储器的限制。比如DOS下,DATA段不能超过64K吧。

运行期分配内存,就是用malloc()之类的函数,在堆上分配内存。   
运行期内存错误,就是运行的时候发生的,比如申请不到内存,内存越界访问,等等。

除了内存外,编译器还做了宏替换,检查类型安全,上面一说的,类的“访问权限”、“成员数据”、“成员函数”这几个概念的“作用域”等等的语法检查,其他的我就不知道了。

三 编译期执行的效率

例子: http://qiezi.javaeye.com/blog/60067
编译期,把每一步操作结果的值都给缓存下来了,效率当然高了,我们使用相同的缓存策略也可以缩短函数的运行时间。

运行期执行的函数则没有这个优点,它和普通的函数没有区别,不同点在于它在编译的时候运行。把编译器看成一种动态语言运行环境,那么编译“编译期执行的函数”的过程就像是运行动态语言程序的过程。

如果程序中存在大量编译期执行函数,可能极大地降低编译效率,对于它的使用应该尽量避免。

模板提供的是一种声明式语法,在复杂的静态执行逻辑面前有时候会显得力不从心,编译期执行函数在解决这个问题的同时,却带来了上面这种副作用。

如果能把两者的优点结合起来用函数的语法来写程序,由编译器生成优化的模板代码,这种编译期执行才可以大量使用。

同样,可以写个梯乘的函数,求10000,在编译器和运行期,各写一个例子看看运行结果。就知道编译期做运算的好坏。

四 模板的运用 1 stl 模板是在编译期运行的,所以程序中尽量用stl,除了安全性与规范性好外,stl的一些操作都在编译时执行。

2 ATL ATL 跟com有个区别就是用了模板来取代com的虚拟表。ATL用了大量模板,很多操作都在编译时执行了,
所以编出来的可执行文件,比较小。这个是我自己猜的。

3 泛型编程语言,C++强大(但容易失控的)模板功能使它能在编译期完成许多工作,从而大大提高运行期效率。这个东西比较难,暂时没详细了解。一个不错
的例子:

http://wgysh1987.blog.163.com/blog/static/67986941200952454710401/

a

b

c

d

e

f

时间: 2024-10-24 09:55:44

c++ 编译期与运行期总结的相关文章

String类编译期与运行期分析

字符串与字符串相加--字符串拼接时,有哪些特殊的地方? 在编译期与运行期这2个期间,字符串有何特点? 1.String s = "s1"; String s1 = "s"+1; System.out.println(s=s1); 运行结果:true 编译期时,能确定s1的值--因为s是常量,1也是常量.在编译时,s1的值就已经等于s1了. 所以,输出时,s1对象不会创建,直接指向s所指的这个对象. 2.String s = "s1"; int s

深入分析Java的编译期与运行期

不知大家有没有思考过,当我们使用IDE写了一个Demo类,并执行main函数打印 hello world时都经历了哪些流程么? 想通过这篇文章来分析分析Java的执行流程,或者换句话说想聊聊Java的编译期与运行期的流程. 开门见山 编译期间都做了什么 运行期间都做了什么 1. 开门见山 public class MyApp { public static void main(String[] args) { System.out.println("hello world"); } }

constexpr:编译期与运行期之间的神秘关键字

Scott Meyers在effective modern c++中提到"If there were an award for the most confusing new word in C++11, constexpr would probably win it." 由此可见,constexpr确实是比较难以让人理解.加之其在C++11和14中的标准略有不同,也加剧了这种难度. 参考几本经典教材(C++ primer, effective modern C++, a tour of

java 19 - 4 编译期异常和运行期异常的区别

1 /* 2 编译时异常和运行时异常的区别 3 编译期异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译 4 运行期异常:无需显示处理,也可以和编译时异常一样处理 5 */ 6 import java.text.ParseException; 7 import java.text.SimpleDateFormat; 8 import java.util.Date; 9 public class ExceptionDemo { 10 public static void main(

异常-编译期异常和运行期异常的区别

1 package cn.itcast_03; 2 3 import java.text.ParseException; 4 import java.text.SimpleDateFormat; 5 import java.util.Date; 6 7 /* 8 * 编译时异常和运行时异常的区别 9 * 编译期异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译 10 * 运行期异常:无需显示处理,也可以和编译时异常一样处理 11 */ 12 public class Except

JVM总结(六):早期(编译期)优化

这节我们来总结一下JVM编译器优化问题. JVM编译器优化 Javac编译器 Javac的源码和调试 解析与填充符号表 注解处理器 语法分析与字节码生成 Java语法糖 泛型和类型擦除 自动装箱.拆箱与遍历循环 条件编译 JVM编译器优化 JVM的编译器可以分为三个编译器: 1.前端编译器:把.java转变为.class的过程.如Sun的Javac.Eclipse JDT中的增量式编译器(ECJ). 2.JIT编译器:把字节码转变为机器码的过程,如HotSpot VM的C1.C2编译器. 3.A

Javac早期(编译期)

从Sun Javac的代码来看,编译过程大致可以分为3个过程: 解析与填充符号表过程. 插入式注解处理器的注解处理过程. 分析与字节码生成过程. Javac编译动作的入口是com.sun.tools.javac.main.JavaCompiler类,上述3个过程的代码逻辑集中在这个类的compile()和compile2()方法中,整个编译最关键的处理就由图中标注的8个方法来完成,下面我们具体看一下这8个方法实现了什么功能. 解析与填充符号表 解析步骤由上图中的parseFiles()方法(过程

早期(编译期)优化

相当多新生的java语法特性,都是靠编译器的“语法糖”来实现,而不是依赖虚拟机的底层改进来支持,java中即时编译器地运行期的优化过程对于程序运行来说更重要,而前端编译器在编译期的优化过程对于程序编码来说关系更加密切. Javac编译器 编译过程大致可以分为3个过程,分别是解析与填充符号表过程,插入式注解处理器的注解处理过程,分析与字节码生成过程.其步骤之间的关系与交互顺序如图所示: 解析与填充符号表 解析步骤包括词法分析和语法分析两个过程.词法分析是将源代码的字符流转变为标记(Token)集合

Java编译期和运行期

Q.下面的代码片段中,行A和行B所标识的代码有什么区别呢? ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ConstantFolding {       static final  int number1 = 5;       static final  int number2 = 6;       static int number3 = 5;       static int number4= 6;