编译期与运行期
2009-12-31 15:19
155 查看
看这样一段代码。
出现了很有趣的结果,在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() 被成功调用。如果能够理解这两个在不同时间作用的概念,这个问题就很好理解.
由这个问题,就引出了编译期和运行期的概念。
顾名思义,编译期指的是编译器在编译代码的时候,而运行期指的是程序运行的时候。
在大型系统中,log信息的管理是一项十分庞大的工程。通常来说log分为两种,一种是调试的log信息,一种是出错的Log信息,前者只对本模块的开发工程师可见,后者本系统的工程师和测试工程师可见。由此就引入了log信息的管理,我们通常有release版本和debug版本,release版本的log信息只限于出错log,debug则输出本模块的log。闲话扯远了,回归正题。
如何来控制log信息的输出,也就是程序如何判断是否输出log。很明显我们需要判断语句,那么如何使用判断语句才能保证最好的效果。这里有两种方法。
设定全局const变量,在打印函数中根据全局变量来判断。这样的实现也很简洁,修改起来也很方便。
const bool g_debug 1
void Log(char* str)
{
if (g_debug){
printf(str);
}
}
还有一种方法,利用宏来控制Log的输出,用全局宏代替全局变量,宏函数代替全局函数。
#define DEBUG
#ifdef DEBUG
#define LOG(m) /
{/
printf(m);/
}/
#else
#define LOG(m)
#endif
有经验的程序员肯定一眼就看出来第二种Log输出方式比较好。第一种的判断是在运行期,而第二种的判断是在编译期。第一种在每次运行log函数的时候都会去判断全局变量,而第二种是在编译的时候就已经将不需要的Log信息定义为空。因为编译消耗的时间是一次性的,而运行的效率是直接呈现给用户的。由这种节约时间的方法,我们可以发现把很多函数的判断和计算放在编译期,会大大节约运行的时间,提供运行效率,但是编译器并不是万能,所以编译期能做的工作还是十分的有限。
#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 main() { 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() 被成功调用。如果能够理解这两个在不同时间作用的概念,这个问题就很好理解.
由这个问题,就引出了编译期和运行期的概念。
顾名思义,编译期指的是编译器在编译代码的时候,而运行期指的是程序运行的时候。
在大型系统中,log信息的管理是一项十分庞大的工程。通常来说log分为两种,一种是调试的log信息,一种是出错的Log信息,前者只对本模块的开发工程师可见,后者本系统的工程师和测试工程师可见。由此就引入了log信息的管理,我们通常有release版本和debug版本,release版本的log信息只限于出错log,debug则输出本模块的log。闲话扯远了,回归正题。
如何来控制log信息的输出,也就是程序如何判断是否输出log。很明显我们需要判断语句,那么如何使用判断语句才能保证最好的效果。这里有两种方法。
设定全局const变量,在打印函数中根据全局变量来判断。这样的实现也很简洁,修改起来也很方便。
const bool g_debug 1
void Log(char* str)
{
if (g_debug){
printf(str);
}
}
还有一种方法,利用宏来控制Log的输出,用全局宏代替全局变量,宏函数代替全局函数。
#define DEBUG
#ifdef DEBUG
#define LOG(m) /
{/
printf(m);/
}/
#else
#define LOG(m)
#endif
有经验的程序员肯定一眼就看出来第二种Log输出方式比较好。第一种的判断是在运行期,而第二种的判断是在编译期。第一种在每次运行log函数的时候都会去判断全局变量,而第二种是在编译的时候就已经将不需要的Log信息定义为空。因为编译消耗的时间是一次性的,而运行的效率是直接呈现给用户的。由这种节约时间的方法,我们可以发现把很多函数的判断和计算放在编译期,会大大节约运行的时间,提供运行效率,但是编译器并不是万能,所以编译期能做的工作还是十分的有限。
相关文章推荐
- String类编译期与运行期分析
- C++ 编译期与运行期
- Java编译期和运行期
- c++ 编译期与运行期总结
- spring 的事务回滚 异常exception 和 编译期异常和运行期异常
- Java编译期优化与运行期优化技术浅析
- Effective C++第七章-模板和泛型编程之编译期多态(运行期多态)和隐式接口(显式接口)
- 静态变量在什么时候加载?编译期还是运行期?静态代码块加载的时机呢?
- jvm原理(3)编译期常量与运行期常量的区别及数组创建本质分析
- C++编译期与运行期
- C++中多态如何在编译期和运行期实现
- JVM学习笔记十一 之 编译期优化和运行期优化
- 关于编译期和运行期一些理解
- C++编译期多态与运行期多态
- ios 编译期和运行期
- C++编译期多态与运行期多态
- C++编译期多态与运行期多态
- 【随想】关于【编译期确定与运行期确定】和【静态内存与动态内存】
- Java函数调用过程-编译期-运行期
- C++ - 显示接口&运行期多态 和 隐式接口&编译期多态