第六章:探索程序

头文件 - 源代码
区别:
1. 默认情况下,头文件不参与编译,而每个源文件自上而下独立编译
2. 头文件存放:变量,类型,函数的声明;宏,结构体和类的定义
源文件存放:变量的定义初始化,函数的定义实现放于源文件中
//.h
extern int a;
//.cpp
int a=1;
各类型变量的声明定义:
//常函数
void fun() const;
void CTest::fun() const{}
//静态成员函数
static void fun();
void CTest::fun(){}
//虚函数
virtual void fun();
void CTest::fun(){}
//纯虚函数()不需要实现
virtual void fun()=0;
总结:
类中的成员函数在对应的源文件中定义时,一定要加上类名作用域
类中普通成员属性和 const 成员属性在构造函数中的初始化参数列表进行初始化定义,而静态成员属性要
在源文件中单独定义
静态成员函数,虚函数定义去掉关键字
头文件重复包含:
问题 :
如果在一个头文件中创建一个类,然后另外两个头文件又都用到了这个头文件,在源文件中使用了另外
两个头文件,那么第一个头文件中的类就会被创建两次,会出现重定义的错误。
解决方案:
1.#pragma once: 告诉编译器,当前的头文件在其他的源文件中只包含一次
2. 宏逻辑判断
对比:
1.#pragma once 相对来说效率高
2. 基于宏逻辑判断,在大量头文件时,编译速度降低,耗时增加,而且需要考虑宏重名的问题。
程序生成过程:
程序生成过程:
预处理:
将原文件( .cpp )初步处理,生成预处理文件(
.i ):
1. 解析 #include 头文件展开替换。
2. 宏定义指令: #define 宏的替换, #undef 等。
3. 预处理指令:解析 #if #ifndef #ifdef #else #elif #endif 等。
4. 删除所有注释。
编译期
将预处理后的文件(
.i )进行一系列词法分析、语法分析、语义分析及优化,产生相应的汇编代码文件
.asm )。
汇编期
将编译后的汇编代码文件( .asm )汇编指令逐条翻译成目标机器指令,并生成可重定位目标程序的 .obj
文件,该文件为二进制文件,字节编码是机器指令。
链接期
通过链接器将多个目标文件( .obj )和库文件链接在一起生成一个完整的可执行程序。
编译期运行期:
编译期 :是指把源程序交给编译器编译、生成的过程,最终得到可执行文件。
运行期 :是指将可执行文件交给操作系统执行、直到程序退出,把在磁盘中的程序二进制代码放到内存
中执行起来,执行的目的是为了实现程序的功能。
注意: 数组越界是运行期错误,用变量定义数组是编译期错误
int len = 20;
int arr[len]; //编译期错误
//-------------------------------------
int len = 0;
cin >> len;
int* p = new int[len]; //运行期
//p[100] = 10; //数组越界:运行期错误
类和对象:
类:编译期的概念,包括类成员函数,静态属性,作用域,访问修饰符
对象:运行期的概念实例,引用,指针
class CFather {
public:
virtual void fun() {
cout << "CFather::fun" << endl;
}
};
class CSon :public CFather {
private: //编译期的限制
virtual void fun() {
cout << "CSon::fun" << endl;
}
};
CFather* pFa = new CSon;
pFa->fun(); //Cson::fun
private 是编译期的限制,在运行时无效,可以调用子类的 fun 函数
int len = 20;
int arr[len]; //编译期错误
//-------------------------------------
int len = 0;
cin >> len;
int* p = new int[len]; //运行期
//p[100] = 10; //数组越界:运行期错误
class CFather {
public:
virtual void fun() {
cout << "CFather::fun" << endl;
}
};
class CSon :public CFather {
private: //编译期的限制
virtual void fun() {
cout << "CSon::fun" << endl;
}
};
CFather* pFa = new CSon;
pFa->fun(); //Cson::fun宏:

宏替换优缺点:
优点:
1. 使用宏可以替换在程序中经常使用的常量或表达式,在后期程序维护时,不用对整个程序进行修
改,只需要维护、修改一份宏定义的内容即可。
2. 宏在一定程度上可以代替简单的函数,这样就省去了调用函数的各种开销,提高程序的运行效率。
缺点:
1. 不方便调试。
2. 没有类型安全的检查
3. 对带参的宏而言,由于是直接替换,并不会检查参数是否合法,也并不会计算求解,存在一定的安
全隐患。
宏的用法:
#undef 取消宏定义
#define A 10
cout<<a<<endl;
#undef A//取消宏定义
int A=20;
cout<<A<<endl;
//#将宏参数转为字符串,相当于加了双引号
#define D(PARAM) #PARAM
fun(D(123));
//#@将宏参数转为字符,相当于加了单引号
#define D(PARAM) #@PARAM
fun(D(1));
//##起拼接作用
#define D(PARAM) int a##PARAM =100;
D(2);
cout<<a2<<endl;
inline 内联函数注意:
内联是以 代码膨胀(复制)为代价,空间换时间,仅仅省去了函数调用的开销,从而提高函数的执
行效率 。 如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方
面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。
类、结构中在的类内部声明并定义的函数默认为内联函数,如果类中只给出声明,在类外定义的函
数,那么默认不是内联函数,除非我们手动加上 inline 关键字。
以下情况不宜使用内联:
(1) 如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
(2) 如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
(3) 类的构造函数和析构函数容易让人误解成使用内联更有效。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橙栩源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值