IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++|常见知识点归纳 -> 正文阅读

[C++知识库]C++|常见知识点归纳

常见知识点归纳

<试着归纳一下哈哈,错误的地方欢迎指出来。>

1 C++11新特性
? nullptr,智能指针,auto跟decltype,for循环按区间迭代,继承构造(using A::A;),unordered_map跟unordered_set,array数组等。

2 auto跟decltype的使用(auto跟decltype的区别)
? auto关键字,就是让编译器根据初始化来推断它的数据类型。
? decltype关键字,也是让编译器来推断,但它不需要初始化,但需要提供一个东西或者对象给它。

auto num1; //错误,auto需要初始化
auto num2 = 1.0;//正确

int a = 0;
decltype(a) b; //根据a为int,定义int型变量b

3 继承构造(using A::A;
? 继承构造,如果没有调用到其中的某个具体的构造函数的话,编译器是不会对它产生真正的代码的。
? 调用继承构造,对子类自身的成员可以用初始化表达式(data{1}; )

4 lambda表达式([](int in){return in;};
? 关于捕获问题/类中无法捕获私有成员,需要通过捕获this指针。

5 array(与内置数组、vector的区别)
? array需要给定大小,它分配在栈上,是内置数组的升级版,它比内置数组在使用上更安全也更方便。
? array跟内置数组的区别:array数组,用at()查询,会有越界判断,array可以拷贝构造。
? array跟vector的区别:array数组,大小一开始就需要给定,不能再修改,没办法添加删除。array没有push_back这样的函数使用。

6 unordered_map,unordered_set
? unordered_map无序键值对,底层算法是哈希表,搜索时间复杂度为O(1)
? unordered_map[x] = y;如果x不存在,则新建x-y,如果x存在,则覆盖x的值。
? unordered_map.insert(pair…)的话,则如果x存在会插入失败,返回第二个参数为false.返回类型是它的迭代器。
? unordered_set 就是只有键,没有值,或者说它的键等于它的值,就是一个序列,元素不会重复。
? map,是有序的,它的底层算法是红黑树,搜索时间复杂度为O(logn)。

7 move移动构造(A(A&& a)

? 左值:内存中有它实际的地址的变量。
? 右值:即时数,或者临时存在的变量,就是这一句执行完它就生命周期结束释放掉了。
? 右值引用,从move移动构造说起,move移动构造会转移控制权,把右边的数据、指针这些复制过去后,也就是简单的浅拷贝,然后把 右边的数据、指针这些置0或者置空nullptr。通过move移动构造,右边就成了一个空对象,然后右边就被释放了,但是原来的对象以 及被转移了,所以完成了移动构造。

class T{
private:
    int a;
    int *b;
public:
    T(T&& t){	//调用时: T Ta = move(Tb);
        a = t.a;t.a=0;
        b = t.b;t.b = nullptr;
    }
};

8 智能指针(shared_ptr,unique_ptr,weak_ptr)
? 智能指针有三个,shared_ptr,unique_ptr,weak_ptr三个。
? 比较常用的是shared_ptr,它内部采用一个计数的方式,当有引用它时,则计数加一,当释放的时候,计数减一,当计数值为0时它自 动调用析构释放。
? unique_ptr,它首先是用explicit修饰参数构造函数,禁止它的隐式转换,然后删除默认拷贝构造函数、赋值操作符,删除操作就是在 后面加上=delete,这样它实例化后别人就不能从它这里得到,所以它的引用就只有它自己这一个。但是它保留有移动构造move,它可 以转移控制权。
? weak_ptr,它不能单独使用,它必须配合shared_ptr使用。它可以由shared_ptr赋值得到,但是它的引用不会引起shared_ptr的计数 加一,删除也不会引起计数减一。类似在shared_ptr的成环引用时就可以用weak_ptr来解决。
关于成环引用的问题:https://blog.csdn.net/weixin_45963692/article/details/119305458

9 const修饰,static修饰
? const修饰变量,表示变量为常量,初始化后,就是不能修改的。
? const修饰函数,表示该函数不会做出任何改变。
const修饰函数参数,表示在该函数中不会对该参数值修改。
? const修饰对象,这个对象为常对象,可以调用它的常函数,不能改的。
? static修饰变量,表示该变量为静态变量。
? static修饰全局变量、或者函数,则该变量、函数只在该文件中可见,对文件外部是不可见的。
? static修饰局部变量,它只会定义一次,放在全局数据区,在下一次调用时会直接使用,不会再定义它。
? static修饰类成员变量时,则该变量是一个共享数据,它的初始化必须要全局区进行初始化。

? const跟#define的区别:
? #define宏定义是在预处理期展开,然后在编译时把所有用到的地方用宏定义常量替换,不能对它进行调试,生命周期结束于编译期。
? const常量是一个”运行时“的概念,在程序运行时使用,属性为只读。
? 存储方式上,前者不会分配内存,存储在程序的代码段中,后者需要进行内存分配。
? const跟constexpr的区别:

10 inline(与宏的区别)
? inline关键字,建议编译器内联,而实际上有没有内联需要编译器决定,对一些简单函数,会在调用处直接插入代码片段,这样就省去 了函数调用的开销。
? inline与宏的区别:宏是在预处理时做的,内联是编译的时候做的。宏是简单的字符串替代,而内联的话我们可以给它传入参数、返回 参数,然后交给编译器去生成替换的代码片段。

11 new跟malloc区别(delete/free)
? new不需要指定大小,malloc需要指定大小。
? new不需要强制转换类型,malloc需要转换类型。
? new会调用构造函数,可以直接初始化列表赋值,malloc不会调用构造函数且无法直接初始化。
? new属于操作符,特定情况下可以重载操作符,malloc属于函数,一般包含在<stdlib.h>中,不可以重载。
? new分配失败时会抛出bad_alloc异常,而malloc会返回一个nullptr,所以对malloc需要检查是否分配失败(失败返回nullptr)

12 四种转换static_cast,dynamic_cast,const_cast,reinterpret_cast
? static_cast的使用跟C的强制数据类型转换一样,但是当它用在面向对象时,将父类指针转换为子类指针(下行转换),是不安全的。
? dynamic_cast,用于父类指针转换为子类指针的,它会动态检测(与static_cast的区别),如果不成功则返回一个空指针,安全。
? const_cast的话,一般是用在常变量跟普通变量的转换。
? reinterpret_cast的话,重新解释,比如用一个整形的数,来存下指针本身的值,就可以用这个来转换(int* 转换为int)。

13 关键字 extern(extern “C”)
? 关键字extern,声明时表示该变量、函数在别的文件里已经有被定义过了,这里只是声明。
? extern“C”,是C++要使用C函数的时候需要写的声明。因为C++函数重载的功能,C++对函数名的接口是函数名加上参数列表,但是C不 支持,C就是单纯的函数名,所以声明extern“C”是改变它的接口,让C++可以调用C。

14 指针与引用的区别
? 指针,是指向一片内存的起始地址。引用,是这片内存的一个别名。
? sizeof指针,是指针大小,sizeof引用,是这个东西的大小。
? 指针可以不用初始化,可以为空。引用必须初始化,引用不能为空。
? 指针可以改变指向,但是引用初始化之后就不能再改变它引用别人了。
? 指针在使用的时候需要加解引用操作符,引用可以变量名直接使用。

15 理解“面向对象”、“封装”、“继承”、“多态”
? 面向对象,是一种编程的思维,把各个的东西作为各个对象,然后我们依靠这些对象间的关系来进行编程,这更符合我们的实际生活。
? 封装,将这个对象内部作为一个黑盒子,外部是无法知道的,它内部会严格划分访问权限,它会提供接口给外部调用。这样提高了它的 安全性,而且封装后,也就成了模块化编程,减低了程序的耦合性。
? 继承,继承的目的时实现代码复用,在一个现有类上扩展一些属性、功能时,可以直接复用。
? 多态,多态的实现,是由虚函数机制实现的。就是用基类指针指向派生类的时候,可以通过基类指针调用派生类中的具体函数。

16 虚函数、纯虚函数、虚函数表
? 虚函数,在类中成员函数声明时,用virtual修饰,则将它声明为虚函数。当派生类中重写这个虚函数的时候,即可将派生类中重写的这 个具体函数动态绑定到基类的指针,也就是说实现通过基类的指针,调用派生类的具体函数。
? 纯虚函数,就是虚函数之后加上 =0,即把它声明为纯虚函数。有纯虚函数的类称为抽象类,抽象类是不能实例化的,派生类需要对每 一个纯虚函数负责,全部重写后才能实例化。
?虚函数表,当一个类中出现虚函数的时候,编译器就会给它加上一个虚函数表指针vptr,它指向虚函数表。当子类从父类那里继承而来的 时候,会拷贝一个父类的虚函数表,这样在子类重写虚函数的时候,就能覆盖父类的虚函数,当父类指针调用时则通过vptr找到虚函数 表再找到对应的具体虚函数,也就是使派生类的具体函数动态绑定到父类指针。
? 而纯虚函数的话,则是在虚函数表中留空位,也就是留一个值为0,然后当它还没有被重写时,也就是留有空函数指针,此时编译器会 阻止它的实例化。

? 构造函数为什么不能声明为虚函数?首先创建一个对象必须指出它的类型,否则无法创建,然后如果我们把构造函数声明为虚函数,那 也就是说会在运行时才确定调用具体函数,但是此时对象还未创建,这就形成了一个类似死锁的东西。

? 析构函数为什么常常声明为虚函数?如果析构函数不是虚函数的话,当使用父类指针来指向子类对象时,其生命周期结束后会调用父类的析构函数,而不会对子类进行析构,子类申请的内存就丢失了,就造成了析构函数。为了避免这一点,通常将析构函数声明为虚函数。

17 类、结构体与联合体之间的区别
? class与struct的区别:class默认访问权限private,struct默认权限public
? 联合体union,它是一个数据集合,它的数据成员是共用一片内存的,内存长度为联合体中最大的那个数据成员。某一时刻,联合体只 有一个数据成员是有意义的。

//用union判断储存方式是大端还是小端
bool bigending(){
    union{
        unsigned int a_int;
        unsigned char a_char;
    }a;
    a.a_int = 1;		//大端:数据的高字节保存在低地址。
    return a_char == 0;	//如果是bigending,那就是 01 00 00 00,如果是smallending,那就是00 00 00 01
}

18 深拷贝与浅拷贝
? 浅拷贝,就是对着源对象一一复制,对指针也同样直接复制。
? 深拷贝,针对那些有分配内存的对象,因为如果一一复制的话,会导致两个对象的指针是指向同一个东西的。所以深拷贝就需要重新分 配空间,然后再对空间上的数据一一复制。

19 ifndef/define/endif
? 防卫式声明,作用是避免重复定义,如果没有写的话,比如a引用这个头文件,b引用这个头文件,然后当c同时引用a和b时,那一开始 的这个头文件就被定义了两遍,就是一个重复定义的错误了。

20 继承、组合的区别
? 继承,就是从父类继承相同接口,然后自己再加上自己本身的接口。
? 组合,就是A类中有一个成员是B类对象,A类可以通过这个成员对象实现B类的接口,然后自己再加上自己本身的接口。
? 继承是 is a,组合是 has a。
? 典型例子就是,从链表生成栈:https://blog.csdn.net/weixin_45963692/article/details/119305715

21 函数重载跟函数重写
? 重载是指函数名相同但参数列表不相同,重载函数时编译器会根据调用时的参数列表匹配对应的函数,实际上函数名是函数名加上参数 列表,所以虽然重载函数的函数名是一样的,但是编译器对它们的标识是不一样的,实现了函数重载。
? 重写是指在虚函数机制中,子类重写父类的虚函数,函数名相同,参数列表也相同。

22 什么时候一定需要初始化列表
? 常量成员变量,调用基类的构造函数,成员对象的构造
? 构造顺序是:成员对象构造函数 > 基类构造函数 > 常量

23 内存分为哪些部分以及区别
? C++一般分为5个区,堆、栈、全局存储区、常量存储区、自由存储区
? 堆是由程序员手动申请,然后手动释放的。程序员需要对它的生命周期负责,否则只能在程序结束时由操作系统回收。
? 栈是编译器根据需要自动申请分配的。比如临时变量,函数传参pass by value。
? 全局存储区,就存全局变量,静态变量的一个空间。
? 自由存储区
? 常量存储区,就是存常量的一个空间,比如字符串常量的分配。

const char *p = "123abc";// "123abc"为字符串常量,存放在常量存储区
char p[] = "123abc";	 // 分配在栈上

24 迭代器失效问题以及解决方案
? 顺序容器vector中,当erase()的时候,删除元素后返回迭代器,如果单纯it++则会错误(错误的原因是:后部分数据已经往前移了,此时it就已经是下一位了,不该再it++)。
关联容器也有这个问题,在这里有讲讲:https://blog.csdn.net/weixin_45963692/article/details/119305901

25 #include<xxx.h>与#include”xxx.h”的区别
? 前者是在标准库中寻找
? 后者是在当前工作路径中找,比如自己写的头文件

26 C++运行时发生了什么
? 预处理,编译,汇编,链接,可执行程序
? 预处理:先处理宏定义、条件编译指令、特殊符号、注释这些处理
? 编译:编译成汇编代码(.s文件)
? 汇编:将汇编代码转化为机器识别的二进制代码,生成(.obj文件)
? 链接:将程序关联的外部文件关联起来,形成(.exe文件)
? 什么是静态链接,什么是动态链接?

27 volatile
? volatile修饰变量的时候,意思是这个值可能会由其他途径发生修改,如果没加volatile的话,编译器会优化这个数值,当这个数值在某 些阶段内没有发生修改的话,下一次使用的时候编译器就直接使用上一次的值。所以加上volatile,就让编译器不要对它优化,当每次 使用这个变量的时候,都是去内存中读取最新的数值。

28 如何编写一个智能指针
29 C++类型安全是什么意思?
30 函数指针表达跟使用

31 内存对齐相关(计算类的大小)
? 类的内存对齐有两部分,首先是数据类型自身对齐,然后是整个类的数据类型对齐。
? 数据类型自身对齐,数据存放的起始地址为数据类型长度的整数倍。比如int只能0x0000、0x0004。
? 整个类的数据类型对齐,就是按照长度最大的那个数据类型的长度为基准,空余位置则字节填充。

class T0{	//假设从0x0000开始,a:0x0000-0x0003,b:0x0004,c:0x0008-0x0015,而0x0005-0x0007则字节填充。
private:	//a长度为4,只能从0x0000或者0x0004开始,这里可以从0x0000开始。b长度1位,可以任意位开始,所以在0x0004。
    int a;	//c长度为8,只能从0x0000后者0x0008开始,因为这时候内存排到0x0005了,所以只能从0x0008开始,差的填充。
    char b;	//所以sizeof(T0)为16.
    double c;
};
class T1{	//b:0x0000,c:0x0008-0x0015,d:0x0016-0x0019,而0x0001-0x0007、0x0020-0x0023则字节填充
private:	//所以sizeof(T1)为24.
    char b;
    double c;
    int a;
};

? 内存对齐的目的是:提高CPU访问的速度。为什么?

32 C++什么类不能被继承

33 STL六大件
? STL六大件分别是:容器,分配器,迭代器,算法,适配器,仿函数
? 容器,就是用来存放数据的。
? 分配器,为容器的数据提供分配合适的内存。
? 迭代器,就是因为数据的存放是由容器决定的,数据的存储方式对外部是不可见的。容器向外提供迭代器,我们可以用迭代器来进行访 问它而不需要知道它的具体具体和它的寻找方式。
? 算法,基于迭代器去访问容器,于是实现了容器跟算法的分离。
? 适配器,主要就是对已有的容器,隐藏或增加特定的接口以实现新的样貌,符合逻辑需求。比如stack的底层实现是deque。
? 仿函数

34 关于空类指针调用函数的问题
类的成员函数是放在代码区的,函数地址是根据类型去查找的,编译期就确定了它的调用地址,对象调用其成员函数实际上是传入一个this的指针来实现的,但是不需要传入参数时则空对象可以调用,如下。

class T{
private:
    int a;
public:
    void fun1(){cout << "fun1() of void" << endl;};
    void fun2(){cout << "fun2() of *this:" << a << endl;}
    virtual void fun3(){cout << "fun3() of virtual" << endl;}
};
int main(){
    T* p;
    p->fun1();//正确。
    p->fun2();//错误,需要传入this指针给函数,空指针错误。
    p->fun3();//错误,调用虚函数需要访问vptr,空指针错误。
    return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 10:37:50  更:2021-08-02 10:38:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 18:07:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码