如何理解编译期和运行期的概念?它们分别干了什么

本文讨论了编译期和运行期的区别及其在内存分配中的作用。编译期涉及源代码转换成可执行文件的过程,而运行期关注程序执行直至结束的周期。文章还解释了不同阶段内存分配的特点及可能出现的错误。

转自http://topic.youkuaiyun.com/t/20040727/17/3215711.html

 

如何理解编译期和运行期的概念?它们分别干了什么

楼主cathy97(男人练瑜伽好处多) 2004-07-27 17:29:46 在 C/C++ / C++ 语言 提问

一直搞不清二者的实际区别,经常在一些文档里说,编译期分配内存,或在运行期分配内存,编译期错误,运行期错误。如何区分他们,请各位指点哟 问题点数:50、回复次数:11Top

1 楼whyglinux(山青水秀)回复于 2004-07-27 17:44:10 得分 5

编译期是指把你的源程序交给编译器编译的过程,最终目的是得到可执行的文件。运行期指的是你将可执行文件交给操作系统(输入文件名,回车)执行、直到程序执行结束的期间,执行的目的是为了实现程序的功能。Top

2 楼zjxiaoyu(alalei)回复于 2004-07-27 18:04:54 得分 5

编译期分配内存,就是用静态或全局数组。这是在编译的时候确定的。  
  运行期分配内存,就是用malloc()之类的函数,在堆上分配内存。  
  编译期内存错误,就是比如某个数据段DATA段或者CODE段等等,超过跑这个程序的目标机的存储器的限制。比如DOS下,DATA段不能超过64K吧。  
  运行期内存错误,就是运行的时候发生的,比如申请不到内存,内存越界访问,等等。Top

3 楼geesun(还是Geesun!)回复于 2004-07-27 18:07:58 得分 10

上面说的已经很清楚了~  
  比如:  
  char   str[LENGTH]   //这个LENGTH你必须在编译期就能知道他的大小,所以只能是宏定义和const(const   int   LENGTH=100,这个是在编译期间就把100和LENGTH邦定的,以后不能更改的!),这个是在编译期   就能知道的量。  
   
  如果你用int   LENGTH   =100;那这个东西是在运行期间才知道LENGTH的值(运行的时候才把100赋给LENGTH),所以会出现错误!Top

4 楼antijpn(antijpn)回复于 2004-07-27 18:11:23 得分 20

编译期确切地说应该是得到obj文件的过程,得到最后可执行文件的过程叫链接  
   
  编译期最前,最后的是运行期。  
  编译期错误是编译期间就能被编译器捕捉到的错误,譬如定义一个过大数组,不过最常见的还是语法错误或者拼写错误。运行期错误可以也可以是分配一个过大的数组,不过在C++里面这个可以因为new[]或者malloc产生,C里面一般由malloc产生。运行期错误还有表达式中的被0除、越界访问等。  
   
  编译期分配内存并不是说在编译期就把程序所需要的空间在内存里面分配好,而是说在程序生成的代码里面产生一些指令,由这些指令控制程序在运行的时候把内存分配好。不过分配的大小在编译的时候就是知道的,并且这些存贮单元的位置也是知道的。  
  而运行期分配内存则是说在运行期确定分配的大小,存放的位置也是在运行期才知道的。Top

5 楼bluejugar(2046,那年我64.)回复于 2004-07-27 22:09:06 得分 0

轻轻的顶一下,悄悄的离开。Top

6 楼elvahuang(熊熊)回复于 2004-07-27 23:50:55 得分 5

编译简单点说就是将source   code-->汇编语言或。NET中的IL或二进制文件  
  运行就是CPU执行上述编译后的代码Top

7 楼cathy97(男人练瑜伽好处多)回复于 2004-07-28 14:52:31 得分 0

感谢各位的帮助,antjipn所言,  
   
  编译期分配内存并不是说在编译期就把程序所需要的空间在内存里面分配好,而是说在程序生成的代码里面产生一些指令,由这些指令控制程序在运行的时候把内存分配好。不过分配的大小在编译的时候就是知道的,并且这些存贮单元的位置也是知道的。  
   
  问题:  
  1。对于new,也可以指定其分配空间的大小,如int   a   =   new   int[100],那为何编译器不能分配空间,而非要等到运行期才能分配呢?  
  2。编译器分配的存储单元的位置也是知道的,如何理解?我想这个地址应该是虚地址,当程序运行时被加载到内存后,还要映射到真正的物理地址吧。  
   
  另外,请教各位有没有这方面的书可以参考,是不是非要看“编译原理”之类的书,太恐怖了Top

8 楼expert2000(ZLX)回复于 2004-07-28 14:56:06 得分 0

个人认为,编译期的错误一般都是语法错误,运行期的错误都是逻辑错误。(可能以偏概全了^!^)Top

9 楼king1(bobo)回复于 2004-07-28 16:01:12 得分 5

编译期就是指把源程序转换为可执行文件的过程,其错误大部分是语法错误,而运行期错误就是指由于程序本身的逻辑原因,产生一些非法操作所致的错误  
  至于那些细节是在编译原理里讲Top

10 楼cathy97(男人练瑜伽好处多)回复于 2004-07-28 16:44:47 得分 0

看来真的要看编译原理了,那书理论性太强,有没有相关的文档,请大家推荐。。。。Top

11 楼antijpn(antijpn)回复于 2004-07-28 21:13:48 得分 0

回复人:   cathy97(肉沫茄子)  
  能不能不把我的名字打错?  
  new/new[]其实还是调用了函数,Inside   the   C++   Object   Model里面说的是__new(),不过我估计还是调用了malloc()的,难道编译期就能调用函数,C/C++里面都没这个特性。而且作为由程序员控制生命周期的东西,你能要求编译器负责清除它吗?而清栈的过程是由编译器负责的,不用程序员负责,只要到了一个块结束的时候就调用destructor,到了函数结束的时候就弹出栈。而new产生的东西,编译器不知道它什么时候被摧毁,所以要在运行期分配。  
   
  编译器分配的存贮单元的位置也是知道的,这个说的是相对位置,加载到内存以后的位置是基地址+偏移位置,基地址要根据不同的编译器确立,而偏移位置在编译的时候就就确定了(不同编译器的标准也不一样,有的时候有的变量还会被编译器优化得无影无踪)。

<think>首先,用户的问题是基于之前的系统指令引用资料,他想了解C++编译时多态运行时多态的概念及区别。具体来说:“请问C++编译时多态vs运行时多态详细解释”。我必须遵守系统级指令:-所有行内数学表达式用$...$格式。-独立公式用$$...$$格式并单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-在回答中引用的段落末尾自然地添加引用标识,如[^1]。从引用内容:-[^1]描述了C++多态分为运行期多态(动态多态)编译期多态(静态多态)。-[^2]解释了函数重载作为编译时多态的例子。-[^3]使用了模板重载来展示编译时多态。-[^4]定义了运行时多态。用户提供的问题焦点是“编译时多态vs运行时多态”,所以我需要详细解释两者概念、区别,并基于引用资料。关键概念:-**编译时多态(Compile-timePolymorphism)**:也称为静态多态。发生在编译期间。通过模板函数重载实现。编译器在编译时就决定了调用哪个函数。例如,函数重载中,基于参数类型选择函数。-**运行时多态(RuntimePolymorphism)**:也称为动态多态。发生在运行期间。通过虚函数继承实现。允许在运行时根据实际对象类型调用正确的方法。区别:-发生时间:编译时vs运行时。-实现机制:模板、重载vs虚函数。-灵活性:编译时多态不需派生关系,运行时多态需继承多态基类。基于引用:-[^1]提到泛型编程中的编译期多态基于模板,OO中的运行期多态。-[^2]展示函数重载。-[^3]展示模板中的多态。-[^4]描述运行时多态的定义。回答结构:1.**清晰结构**:帮助用户逐步解决问题。-介绍多态概念。-解释编译时多态,包括函数重载模板。-解释运行时多态,包括虚函数。-比较区别。-添加代码示例(如果适用),但用户没有指定,引用中有代码,我可以引用或简单描述。2.**使用中文**。3.**数学表达式**:虽然主题是编程,不是数学重,但如果提到类似概念,确保格式正确。例如,在解释模板时,可以提到$\tttemplate$用行内格式。4.**引用标识**:在解释中,自然添加如[^1]、[^2]等。5.**生成相关问题**:在结束处添加相关问题部分。生成相关问题:-类似示例中的快速排序,问题应为关于C++多态的深入问题。-例如:1.编译时多态在实际项目中的应用案例?2.如何优化运行时多态以提高性能?3.C++20中引入的概念如何影响编译时多态?完整回答:-开头介绍多态。-详细解释编译时多态。-详细解释运行时多态。-区别总结。-添加代码片段参考引用。-结束相关问题。确保真实可靠:基于C++知识,引用来源一致。</think> ### C++编译时多态与运行时多态:概念、区别及详细解释 在C++编程中,多态(Polymorphism)是实现代码复用灵活性的核心机制。C++支持两种多态:编译时多态(也称为静态多态)运行时多态(也称为动态多态)。它们的主要区别在于多态决策的发生时间实现机制。下面我将详细解释两者概念、机制、应用场景及区别,基于您提供的引用资料进行梳理(引用内容基于[^1][^2][^3][^4])。 #### 1. **编译时多态(Static Polymorphism)** 编译时多态发生在代码编译阶段,编译器在编译时就能确定调用的具体函数或方法,无需运行程序。这主要通过两种机制实现:**函数重载****模板**。 - **概念与机制**: - **函数重载(Function Overloading)**:同一作用域内,定义多个同名函数,但参数列表不同(如参数类型、数量或顺序)。编译器根据调用时传入的参数类型,在编译期选择匹配的函数[^2]。 - 例如: ```cpp int Add(int a, int b) { return a + b; } // 整型版本 double Add(double a, double b) { return a + b; } // 双精度版本 ``` 当调用`Add(1, 2)`时,编译器直接选择`int`版本;调用`Add(3.5, 4.5)`则选择`double`版本。 - **模板(Templates)**:泛型编程的基础,编译器在编译时生成具体类型的代码。多态通过模板的具现化(instantiation)实现,编译器根据模板参数类型实例化不同版本[^1][^3]。 - 例如动物类的模板示例[^3]: ```cpp template <typename T> void animalShout(T& t) { t.shout(); } // 模板函数 ``` 当调用`animalShout(dog)`时(`Dog`类型),编译器生成`Dog::shout()`的代码;而调用`animalShout(cat)`则生成`Cat::shout()`的代码。 - **优点**: - **高性能**:无运行时开销,函数调用在编译期解析,提升执行效率[^4]。 - **灵活性**:不需类继承关系,可应用于任意类型(如同一个模板可处理不同类实例)[^3]。 - **缺点**: - **编译时间长**:模板具现化增加编译时间,尤其在大型项目中。 - **错误信息晦涩**:模板错误在编译期报错,信息可能难以理解。 - **应用场景**:常用于STL容器、算法库、数学计算等性能敏感部分,例如`std::vector<T>`或`std::sort`通过模板实现类型无关的操作[^1]。 #### 2. **运行时多态(Dynamic Polymorphism)** 运行时多态发生在程序运行阶段,具体函数调用在运行时根据对象类型动态决定。这主要基于**虚函数(virtual functions)** **继承**机制。 - **概念与机制**: - **虚函数(Virtual Functions)**:在基类中使用`virtual`关键字声明函数,派生类覆盖(override)该方法。通过基类指针或引用调用时,实际执行的函数取决于对象的运行时类型[^4]。 - 示例: ```cpp class Animal { public: virtual void shout() { std::cout << "动物叫声"; } // 虚函数 }; class Dog : public Animal { public: void shout() override { std::cout << "汪汪!"; } // 派生类覆盖 }; int main() { Animal* anim = new Dog(); anim->shout(); // 运行时调用Dog::shout(), 输出"汪汪!" delete anim; } ``` 编译期只确定调用`shout()`,但实际执行哪个版本(`Animal::shout()`或`Dog::shout()`)在运行期通过虚表(vtable)解析[^4]。 - **引用定义**:如[^4]所述,运行时多态允许引用变量在编译时不确定指向哪个对象,只有运行期绑定到具体实例,实现多个运行状态。 - **优点**: - **扩展性强**:在不修改现有代码下添加新子类(如新增`Cat`类覆盖`shout()`)。 - **设计抽象**:支持接口编程,便于实现模式如工厂方法[^1]。 - **缺点**: - **性能开销**:虚表查找增加运行时开销(每次调用需间接寻址)。 - **内存占用**:虚表存储类类型信息,额外消耗内存[^4]。 - **应用场景**:GUI事件处理、游戏对象系统、插件架构等,例如框架中使用基类指针处理多种派生对象[^1][^4]。 #### 3. **编译时多态 vs 运行时多态:关键区别** 总结两者的核心差异如下表: | **方面** | **编译时多态** | **运行时多态** | |------------------|------------------------------------|-----------------------------------| | **发生时间** | 编译期(程序运行前) | 运行期(程序运行时) | | **实现机制** | 函数重载、模板($ \tt template $) | 虚函数、继承 | | **类型绑定** | 静态绑定(编译时确定) | 动态绑定(运行时通过虚表确定) | | **性能** | 高效(无运行时开销) | 稍低(虚表查找开销) | | **灵活性** | 不需类继承关系 | 需继承体系(派生类关系) | | **编译影响** | 编译期错误,模板具现化耗时 | 运行时错误,调试可能复杂 | | **典型应用** | STL容器、泛型算法 | 多态基类系统、动态接口 | #### 4. **为什么需要两种多态?** C++结合两种多态以平衡性能与灵活性[^1]: - **编译时多态**适合优化性能关键部分(如数学计算$ \sum_{i=1}^n a_i $通过模板实现),避免运行开销。 - **运行时多态**用于框架设计,允许运行时对象替换(如UI组件可动态添加新类型)。 在实际项目中,混合使用两种多态是常见实践,例如STL中的`std::function`利用运行时多态,而其内部实现可能使用编译时优化[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值