C++入门学习(cmake、动态库、多态性)

cmake入门了解 

编译器是什么?

编译器读取源代码,生成二进制文件

什么是IDE(集成开发环境)?如VC6.0、VS2012、CodeBlocks等。核心还是编译器,为了方便,全部免去命令形式的操作,取而代之的友好的界面,一键编译等方便的操作。

从.cpp文件到.exe过程

编写C++源代码,并保存为 .cpp 文件 -->编译器编译源代码文件,生成一个目标文件-->将目标文件与库一起链接(使用链接器如 ldg++clang++ 或 link.exe)-->生成可执行文件.exe并运行

make、makefile、cmake、cmakelist的关系:

make作为工具对makefile中的命令进行编译和链接。makefile命令中就包含了调用gcc(也可以是别的编译器)去编译某个源文件的命令。cmake可以更加简单的生成makefile文件给上面那个make用。(最重要的是,可以跨平台生成对应平台能用的makefile。)cmake又要根据一个叫CMakeLists.txt文件去生成makefile。CMake通过CMakeLists.txt 文件来描述项目的构建过程,用户可以在这个文件中定义源代码、库、头文件、编译选项等信息,从而让CMake自动生成相应的构建文件。

https://i-blog.csdnimg.cn/blog_migrate/c9245cf4c2f0baac835c63ec1fa7e4b2.png

main函数是什么?

编程语言像C/C++/C#/JAVA 等main主函数作为程序入口,程序从main()主函数的第一句代码开始执行,直到main函数的最后一句代码程序运行结束,结束后程序退出,申请的所有内存空间等被回收。

c++为什么分为头文件和cpp文件

C++ 支持将接口(声明)和实现(定义)分开。头文件通常包含函数、类、模板等的声明,而源文件包含它们的具体实现。

提高编译效率:头文件通常只包含声明,它们可以在多个源文件中被包含而不需要重新编译,允许开发者在不同的源文件中重用相同的接口。

利于接口隐藏:头文件可以作为模块的接口,而源文件包含实现细节。这有助于隐藏实现细节,只暴露必要的接口给其他模块

动态库

C++内存管理:理解堆、栈、指针,避免内存泄漏

是一块用于动态分配内存的区域,存放的是通过newdelete关键字来分配和释放的对象。堆上的内存需手动管理,如果不及时释放,就会造成内存泄漏。

是一种自动分配和释放的内存区域。在函数调用时,局部变量和函数参数会在栈上分配内存,当函数结束时,栈上的内存自动释放。一般函数在栈上。

通过指针,我们可以访问堆上分配的内存。

在 C++ 中,你可以使用 new 操作符来在上动态申请内存。下面是一个示例,展示如何申请一个 int 类型的指针 p 并将其存放在堆上:

int* p = new int; // 在堆上申请一个 int 类型的内存空间,并将其地址赋给指针 p

这个代码完成了两件事: 

  • 使用 new 关键字在堆上分配了足够的内存空间来存储一个 int 类型的值。
  • 将分配到的内存地址赋给指针 p

 注意,当你使用 new 在堆上分配内存时,你需要负责后续的内存管理。这意味着,当你不再需要这块内存时,你应该使用 delete 操作符来释放它,以避免内存泄漏(程序持续运行,不释放的内存会逐渐累积,最终可能导致程序或整个系统可用内存不足。):

delete p; // 释放之前分配给 p 的内存

如果你申请了一个数组,应该使用 delete[] 来释放内存:

int* pArray = new int[10]; // 在堆上申请一个 int 类型数组的内存空间
// ...
delete[] pArray; // 释放数组占用的内存

想象你在一个图书馆里借了一本书,new int 就像是你向图书馆管理员请求一个空书架,管理员会给你一个编号,告诉你这个书架现在归你使用。这个编号,就是我们的指针 p。你有了一个地方来存放你的书,也就是你的 int 类型的数据。new 这个操作,就像是你告诉管理员:“我要一个新书架,不要旧的。”当你读完书后,你决定将书归还给图书馆,让他们可以回收这个空间,给其他需要的人使用。这相当于在编程中使用 delete p; 来释放指针 p 指向的内存。

如果你归还了书,却没有让图书馆工作人员知道这个书架现在空了(p 在释放内存后未设置为 nullptr),会发生什么呢?

再次使用这个编号去查找书,你可能会空手而归。(指针指向的内存已经被释放,但指针仍然指向那个位置,导致无法访问有效数据

错误地认为书架上还有书(数据),尝试再次申请借阅(尝试访问已经被释放的内存,可能会导致程序错误或崩溃)

其他读者可能会用这个编号去错误地取书(数据),或者尝试在那个书架(空间)上放置自己的书(安全漏洞,可能导致数据覆盖或未授权的访问)

C++内存管理:理解堆、栈、指针,避免内存泄漏-腾讯云开发者社区-腾讯云 (tencent.com)

动态库与静态库区别

用一个比喻来描述动态库和静态库的区别:

动态库
想象一辆公共汽车,任何人都可以在任何时间上车(加载库),并在需要的时候下车(卸载库)。车上的座位(内存)是共享的,不同的乘客(程序)可以使用相同的座位,但不需要拥有它。如果公共汽车需要维修或升级,只需更换车辆,所有乘客都能享受到改进,无需额外费用。

静态库
想象一辆私家车,当你购买它时,它包含了所有你需要的部件(代码)。每次出行(运行程序),你只能使用这辆车和它的部件。如果你想更换部件或升级,你需要自己掏钱购买新的部件并安装。每次出行,无论是否需要,你都必须携带所有部件,即使有些部件在某些行程中并未使用。
 

如何把一个函数导出一个动态库

c++相关函数和类的dll导入及导出(VScode)-CSDN博客

面向对象的多态性

多态:当不同的对象去完成某一个行为时会产生出不同的状态 “一个接口,多种方法”

或者说,不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象买票半价。

函数继承中构成多态的条件:

  • 通过基类的指针或者引用调用虚函数
  • 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写(覆盖)

【C++】多态(举例+详解,超级详细)_c++多态-CSDN博客

虚函数

虚函数是实现多态(动态绑定)/接口函数的基础

可以定义一个基类的指针, 其指向一个继承类, 当通过基类的指针去调用函数时, 可以在运行时决定该调用基类的函数还是继承类的函数

C++面试题之虚函数(表)实现机制_虚函数表是怎么实现的-CSDN博客

接口继承

 以【C++】多态(举例+详解,超级详细)_c++多态-CSDN博客其中一个代码为例:

函数利用父对象指针来访问子对象,然后根据子对象的函数来调用。虚函数的重写是接口继承,实现重写

两个类 AB,其中 B 继承自 A。基类 A 中有虚函数 func 和 虚函数testtest调用了func,而派生类 B 重写了 func 函数。注意, B 中的 func 函数重写了类A 中的 func,它们具有不同的默认参数值。(这里重写的定义我查了,默认参数不同不构成重载)主函数中创建了 B 类的一个实例,并通过基类指针 p 调用了 test。 

由于 test 函数在 A 中定义,调用的是 A 中的 test 函数,,test 函数内部调用的是 func 函数。而p 实际上指向 B 类的对象,又由于 func 是虚函数重写使得在运行 p->test() 时,实际调用的是 B 中的 func 函数的B->

但由于默认参数在编译时确定(而非运行时),因此使用的是 A 中定义的默认参数 1

补充:默认参数的行为

在C++中,默认参数是在编译时解析的。当通过基类指针或引用调用虚函数时,默认参数值是根据基类中的定义来确定的,而不是根据实际调用的派生类中的。

代码运行结果是B->1。 

STL标准模板库——数据类型的多态

在C++中,标准模板库(STL)通过模板机制体现了在数据类型上的多态性。STL中的容器、算法和迭代器都是通过模板来实现的,这使得它们可以处理不同类型的数据,不需要为每种数据类型单独实现一套代码。

模板机制

C++的模板机制是实现多态性的基础。模板允许你定义一个通用的类或函数,而不需要指定具体的类型。模板参数可以在实例化时被具体的类型替换。

模板类

模板类允许你定义一个通用的类,其中的某些成员可以是任意类型。例如,std::vector是一个模板类,可以存储任意类型的元素。

template <typename T>
class vector {
    // 类的实现
};

使用时可指定具体类型:

std::vector<int> intVector; // 存储int类型的元素
std::vector<std::string> stringVector; // 存储std::string类型的元素
模板函数

模板函数允许你定义一个通用的函数,其中的某些参数可以是任意类型。例如,std::sort是一个模板函数,可以对任意类型的容器进行排序。

template <typename RandomIt>
void sort(RandomIt first, RandomIt last) {
    // 函数的实现
}

容器

STL中的容器类(如vectorlistmap等)都是模板类。例如,std::vector<T>可以存储任意类型的元素T,无论是基本数据类型(如intdouble)还是用户定义的类型(如自定义的类)。

std::vector<int> intVector = {1, 2, 3, 4, 5};
std::list<double> doubleList = {1.1, 2.2, 3.3};
std::map<std::string, int> stringToIntMap = {{"one", 1}, {"two", 2}};

算法

STL中的算法(如std::sortstd::findstd::transform等)也是通过模板实现的。这些算法可以应用于不同类型的容器和迭代器。

std::vector<int> numbers = {3, 1, 4, 1, 5, 9};
std::sort(numbers.begin(), numbers.end()); // 对int类型的vector进行排序

std::vector<std::string> words = {"apple", "orange", "banana"};
std::sort(words.begin(), words.end()); // 对std::string类型的vector进行排序

迭代器

迭代器是STL中连接容器和算法的桥梁。迭代器也是模板化的,可以指向不同类型的容器和元素。 

std::vector<int>::iterator it = numbers.begin(); // 指向int类型vector的迭代器
std::vector<std::string>::iterator wordIt = words.begin(); // 指向std::string类型vector的迭代器

 

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值