(嵌入式八股)第2章 C++(二)
2.11 静态链接与动态链接
在软件开发中,静态链接和动态链接是两种常见的链接方式,它们决定了程序如何在编译时或运行时与外部库进行连接。
静态链接(Static Linking)
定义:
- 静态链接是在编译过程中将需要的库代码(如静态库
.a
或.lib
文件)直接嵌入到生成的可执行文件中的过程。 - 这种方式将所有的库文件和函数的代码打包到可执行文件内,使得生成的程序在运行时不依赖外部的库文件。
特性:
- 在编译时,链接器会将静态库的内容复制到最终的可执行文件中。
- 一旦程序生成并执行,不再依赖外部库文件。
- 生成的可执行文件通常较大,因为它包含了所有必要的库代码。
动态链接(Dynamic Linking)
定义:
- 动态链接将链接过程推迟到程序运行时,由操作系统加载所需的动态链接库(DLL,
.so
文件)。 - 动态链接库在程序运行时被加载到内存中,多个程序可以共享同一个动态链接库的实例。
特性:
- 可执行文件在运行时会查找并加载所需的动态链接库文件(如
.dll
或.so
)。 - 程序不将库代码打包到可执行文件中,因此生成的可执行文件通常比静态链接的文件小。
静态链接与动态链接的区别
2.12 静态链接与动态链接的优缺点?
静态链接的优缺点
优点:
- 程序独立运行,不依赖外部的库文件。
- 不需要在运行时检查库文件的存在,程序启动更快。
缺点:
- 如果多个程序使用相同的库,每个程序都要包含一份相同的库,造成磁盘空间浪费。
- 更新库时需要重新编译和链接所有依赖该库的程序。
动态链接的优缺点
优点:
- 多个程序可以共享同一个动态链接库,节省了磁盘空间和内存。
- 如果库的版本更新,只需更新动态链接库,而不需要重新编译所有依赖库的程序。
- 支持插件机制,程序可以在运行时加载或卸载库。
缺点:
- 程序在运行时依赖外部库文件,若库文件丢失、版本不匹配或发生变化,可能导致程序无法正常运行。
- 程序启动时会稍微慢一些,因为需要在运行时加载动态链接库。
总结
2.13 静态存储和动态存储
静态存储和动态存储是计算机编程中两种不同的内存分配方式。
静态存储(Static Storage)
定义:
- 静态存储指的是在编译时就已经分配并且在程序整个生命周期中存在的内存区域。这些内存位置在程序启动时就被分配,并且在程序结束时释放。
特点:
- 内存分配时机:在程序编译时确定内存的大小和生命周期,内存分配是在编译阶段完成的。
- 生命周期:静态存储区的内存从程序开始执行到程序结束期间都存在,生命周期贯穿整个程序运行。
- 内存管理:编译器自动管理静态存储区的内存,不需要程序员手动进行内存的分配和释放。
适用场景:
- 适用于需要在多个函数间共享数据的情况。
- 适用于生命周期固定且不需要在运行时动态变化的变量。
示例:
- 全局变量:在程序中的任何地方都可以访问和修改。
- 静态变量:通过
static
关键字声明的变量,它在函数内部声明时,其值会在函数调用之间保持不变。
globalVar
是一个全局变量,在整个程序的生命周期内都存在。staticVar
是一个静态变量,它在每次调用func()
时不会被重新初始化,而是保持上次调用时的值。
动态存储(Dynamic Storage)
定义:
- 动态存储指的是程序在运行时根据需求动态分配和释放内存。动态内存分配在程序运行时进行,可以在运行时根据实际情况决定需要分配多少内存。
特点:
- 内存分配时机:内存分配在程序运行时进行,内存的大小和生命周期由程序动态决定。
- 生命周期:动态存储区的内存仅在程序员明确要求时分配,并且需要手动释放,否则可能会导致内存泄漏。
- 内存管理:程序员必须负责在合适的时间使用
malloc()
、calloc()
、new
等函数分配内存,并使用free()
、delete
等函数释放内存。
适用场景:
- 适用于内存需求在程序运行时才知道或者变化较大的情况。
- 适用于灵活的数据结构,如链表、树、图等动态数据结构。
示例:使用 new
(C++)进行动态内存分配:
- 使用
new int(10)
分配了一个整数的动态内存,并将值初始化为 10。 - 使用
delete
释放内存,防止内存泄漏。
示例(使用 malloc
):在 C 中使用 malloc
进行动态内存分配:
malloc
动态分配了内存,并手动赋值 10
。free
函数释放内存,防止内存泄漏。静态存储与动态存储的区别
2.14 类与对象相关概念
类与对象的基本概念
成员变量 & 成员函数:
访问控制:
private
:仅类的内部成员函数可以访问。public
:可以被类外部访问。protected
:子类可以访问,但外部无法访问。class
默认成员是private
,struct
默认成员是public
。
访问对象成员的三种方式:
对象名.成员名
(适用于对象)引用名.成员名
(适用于对象的引用)对象指针->成员名
(适用于指针)
类的构造 & 析构
构造函数:
- 如果没有定义构造函数,编译器会自动提供默认构造函数和复制构造函数。
- 但如果定义了任何构造函数,编译器不会再自动提供默认构造函数。
对象初始化:
- 创建对象时,必须指定构造函数。
- 定义对象数组时,必须确保类有默认构造函数,否则会编译错误。
析构函数:
- 对象消亡时自动调用,完成资源释放。
静态成员
静态成员变量:
- 只存在一份,所有对象共享。
- 在类的外部需要显式初始化:
int 类名::静态变量名 = 值;
静态成员函数:
- 不属于任何具体对象,可以通过类名直接调用
类名::静态函数();
- 不能访问非静态成员变量,也不能使用
this
指针。
常量 & 引用
常量对象:
- 只能调用
const
成员函数。
常量成员 & 引用成员:
- 必须在构造函数的初始化列表中初始化,不能在构造函数体内赋值。
封闭类(包含成员对象的类)
封闭类的构造 & 析构顺序:
友元与 this 指针
友元(friend):
- 友元可以访问类的私有成员。
- 友元关系不能传递。
this 指针:
- 指向当前成员函数所属的对象。
- 静态成员函数中不能使用
this
指针。
类 vs 对象
类是模板,对象是实例:
总结
C++ 的类是面向对象编程(OOP)的基础,理解成员访问、构造析构、静态成员、常量、友元、this 指针等概念对于掌握 C++ 至关重要。这些规则确保了 C++ 的封装性、继承性、多态性等特性能够高效运行。
2.15 访问类的成员使用点号.来访问
使用点号.来访问
创建对象以后,可以使用点号.来访问成员变量和成员函数,这和通过结构体变量来访问它的成员类似。以下是一个简单的例子来说明如何通过对象访问类的成员:
创建对象:
我们通过 Person person; 创建了一个 Person 类的对象 person。
访问成员变量:
通过 person.name 和 person.age 来访问和修改对象的成员变量。
调用成员函数:
通过 person.introduce() 来调用成员函数 introduce,输出对象的属性。
使用对象指针
在 C++ 中,指向对象的指针非常重要,尤其是在动态内存分配、类的继承、虚函数和多态等方面。通过指针,我们可以更灵活地管理对象的生命周期,并且可以在运行时动态分配和访问类的成员。在上个例子
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
作者简介:仅用几个月时间0基础天坑急转嵌入式开发,逆袭成功拿下华为、vivo、小米等15个offer,面试经验100+,收藏20+面经,分享求职历程与学习心得。 专栏内容:这是一份覆盖嵌入式求职过程中99%问题指南,详细讲解了嵌入式开发的学习路径、项目经验分享、简历优化技巧、面试心得及实习经验,从技术面,HR面,AI面,主管面,谈薪一站式服务,助你突破技术瓶颈、打破信息差,争取更多大厂offer。