C++学习记录

C++学习记录,第1张

C++学习记录 前言
  • 此处主要记录,c++面向对象这部分知识,有助于快速上手其他语言!
  • 永远要记住:限制我们发展的永远是我们自己的认知,而不是别人。
  • 心态:同样的环境,同样的氛围,总有人比我们发展的更好,总有人发展的不如我们。
  • 首推的学习文档:https://en.cppreference.com/w/
1. 从c到c++,概述
  • c++是c的超集,C++增加了很多的头文件,不要在意130
  • C++包括四种编程范式:面向过程(STL)、面向对象(类和对象)、泛型编程(模板)、函数式编程(Lambda)
  • 实现语言的时候,大多数情况下使用的是面向过程、面向对象的范式;当相关的泛型能提高开发效率的情况下,才考虑使用(泛型、函数式编程)。
  • 按照编程范式学习其他编程语言,如java.
  • 按照编程范式进行分门别类的学习
# 一、面向过程:STL queue类 stack类 deque(double-endend queue)
  • 这部分很灵活,可以用来实现栈,队列等
Strings library unordered_map
  • 提供了非排序,使用哈希表实现;
  • map是排序,使用了红黑树实现
编码规范

百度+谷歌
阿里+谷歌

习题练习

#245. 货仓选址->std::vector

  • string的使用
    #166. 字符串 *** 作1->std::basic_string
    string: find_first_of函数并不是搜素某个特定的字符串,而是搜寻参数字符串中任意一个字符的出现

  • map的使用
    #216. 获取姓名并排序1->std::map

  • set的使用
    #287. 合并果子->std::priority_queue
    合并果子和哈夫曼编码之间的关系(一模一样)
    哈夫曼解决的是什么问题?求最小的编码长度!

  • 使用类封装大整数:#256. 国王游戏->参考答案
    微扰

# 二、面向对象
  • 封装:我该有的和我该做的
  • 继承:叫一声爸爸,开启财富之门
  • 多态:我就是我,是不一样的烟火
## 封装 类和对象

Fundamental types

类型与变量

类型 = 类型 数据 + 类型 *** 作

成员属性与方法

C++ class与c struct相比,c++ class 中可以放成员方法,而struct不行。
C 语言的struct有单独的命名空间,所以你甚至可以这样定义一个跟类型名字一样的变量;

访问控制权限:public、private、protected、friend
  • 强调作用范围:控制类外对类内的访问权限。(此处好好理解类内和类外)
  • public、private、friend的作用:如,类外重载运算符时,就需要使用friend友元进行声明修饰
  • protected简介
命名空间:namespace
  • 和java、systemverilog中的package是一个道理,防止命名空间内各命名、标识符冲突。
  • 实现一个cout
  • cin、cout也是c++实现的一个对象,不是一个类型也不是一个方法,本质上就是一个对象。
构造函数与析构函数
  • 构造函数:默认构造函数、有参构造函数、转换构造函数、拷贝构造函数
  • 转换构造函数(一个参数的有参构造函数):普通的转换构造函数的应用、函数传值过程中的转换构造函数的作用
  • 拷贝构造函数:拷贝构造函数的基本使用、拷贝构造为什么传入const引用(因为可能需要处理临时的中间变量,所以传入const;防止套娃现象出现,采用引用传入)、赋值拷贝 *** 作
  • 还有一个移动构造函数,c++11帮助c++重回神坛,c++11之前没有将左值和右值区分开。
  • 一个有参构造函数也被称为转换构造函数,
  • 拷贝构造和拷贝赋值运算符是完全不一样的
  • 析构函数:需要资源回收的时候,就需要析构函数
  • 工程项目中,构造函数和析构函数越简单越好,会使用伪构造函数和伪析构函数,体会工厂模式
  • =default和 =delete的作用:明确指出使用或不使用默认的构造函数
    C++学习重点:程序处理流程
3/5法则
  1. 需要析构函数的类也需要拷贝构造函数和拷贝赋值函数。(当类中有些资源是动态申请的,那么它才需要资源回收,可能需要析构函数;但是,对于动态申请出来的这些资源,在发生拷贝行为的时候,通常情况下是发生深拷贝)
  2. 需要拷贝 *** 作的类也需要赋值 *** 作,反之亦然。(当我们为某个类实现拷贝构造的时候,说明这个类一定是有一些特殊的行为,而这种特殊行为也应该被继承在赋值拷贝运算符之中)
  3. 析构函数不能是删除的
  4. 如果一个类有删除的或不可访问的析构函数,那么其默认和拷贝构造函数会定义为删除的。
  5. 如果一个类有const或引用成员,则不能使用合成的拷贝赋值 *** 作。
先调用的构造函数,最后调用析构函数。

这是程序设计的逻辑,先构造的可能为后构造的提供依赖。

转换构造函数(一个参数的构造函数)

调用拷贝赋值运算符,会生成临时匿名对象(调用移动构造函数)

拷贝构造函数 和 拷贝赋值运算符
  • 注意分析拷贝构造和拷贝赋值运算符!
  • 构造对象时,调用的是拷贝构造函数;在给已有对象赋值时,调用拷贝赋值运算符
  • 拷贝构造一定要const修饰,为了兼容处理两种场景(传入的被拷贝对象是const和非const类型)
  • 提供右值引用的复制构造函数的好处,就是 可以节省很多复制对象的开销 ,调用右值引用的复制构造函数,我们可以简单地认为对象直接跑过去了,并没有发生任何复制。
深拷贝和浅拷贝

C++实现的深拷贝

new和malloc的区别(原地构造?实现深拷贝用的还挺多)
  • new构造的时候会调用构造函数并且会初始化
  • delete会自动调用析构函数
属性与方法
  • 成员属性和方法(对象)
  • 类属性和方法(类)
  • 类属性:所有对象访问的都一样,不能使用this指针。定义的时候在前面加上static,全局区?
  • 注意辨别:类属性的声明和定义。
  • 可以通过域限定符和对象去调用
  • const类型的方法与mutable关键字:const声明是为了说明不修改对象内部任何成员属性,主要是给const类型对象使用;mutable就是为了在上述const的修饰下,某些成员属性仍然可以被修改。
const方法
  • 不对当前属性进行更改。
  • const对象不能调用非const对象的方法。
  • const类型方法不能调用非const类型方法
  • const声明是为了说明不修改对象内部任何成员属性,主要是给const类型对象使用
对象与引用
  • 引用在定义的时候要绑定
c++中的结构体与类
  • c++中只是保留了struct关键字,与class的底层实现基本一样。唯一不同的就是默认访问权限不同,struct默认public,class默认private。
  • 为什么要保留struct关键字?
  • 为什么默认访问权限public?
  • 考虑到语言推广成本,收获c用户群体
对象初始化
  • 开辟对象数据区、匹配构造函数、完成构造
  • 开辟对象数据区、匹配拷贝构造函数、完成构造
运算符重载

一个作用域内几个函数名字相同,但是参数列表不同,称为函数重载。(与返回值无关)
重载运算符:注意思考返回引用的作用是什么?
一般需要实现连等 *** 作,对象

类外重载运算符
  • 普通运算符重载
  • 重载cout的左移运算符
类内重载运算符
  • 普通运算符重载
  • 重载下列三个符号,得到的特殊命名:
[] 数组对象
() 函数对象
-> 指针对象
其他重载的知识点 不能重载的5个运算符(五大创世宝石)
  • .成员引用运算符
  • .*成员指针引用运算符
  • sizeof运算符
  • ?:唯一的三目运算符
  • ::作用域 *** 作符
只能在类内部重载的4个运算符
  • ()函数括号运算符(函数对象)
  • []数组方括号运算符(数组对象)
  • ->间接引用运算符(指针对象)
  • =赋值运算符
RVO/NRVO返回值优化
  • 正常情况的拷贝 *** 作
  • 一次优化的情况
  • 二次优化的情况
  • g++使用 -nfo-elide-constructors 选项关掉返回值优化
返回值优化(RVO)

  • 逻辑是优化掉,临时匿名对象!
  • 如果没有这个 *** 作,可能是被编译器优化掉了
  • 大多数编译器会对拷贝构造函数进行返回值优化(替换this指针完成)
练习

std::shared_ptr -----> c++实现简单的智能指针

## 继承

子类将父类所有的属性和方法都继承过来

继承-子类的访问权限


继承权限不影响子类对父类内容的访问?

继承-对外的访问权限


继承权限影响类外部访问子类内部继承自父类这些属性的访问权限

  • 在具有继承关系的情况下,当咱们子类实现拷贝构造的时候,需要显式性的去调用父类的构造函数
  • 怎么实现子类的重载赋值运算符呢?
菱形继承
  • 内存会重复?
  • 实际情况下,一个真实基类吗,多个功能性基类,
  • 思考与虚继承的配合。

代码不是能用就行!命名非常重要!
如果需要多个不允许拷贝的类,不推荐直接把各个拷贝函数delete掉,建议各个类继承自一个不允许拷贝的类!

## 多态

C++多态例子:virtual、override、final

  • 普通成员跟着类走,在编译期就已经确定了
  • 虚函数跟着对象走,在运行期确定,在编译期不能确定
  • virtual 、 override和final的关键字的配合,控制是否覆盖父类同名方法,override是为了规范代码的语义,不是必须要写的,final禁止子类中出现与父类同名的函数,终止虚函数
  • final:禁止类继承、禁止虚函数重载
override
  • 为什么要有这个关键字?
  • final关键字的应用场景:父类中有一个方法需要在所有地方都表示的一模一样,不想让子类去修改,就把相关函数标记成final
虚函数为什么跟着对象走?

对象的前8个字节,存储的是一个虚函数表的地址,可以通过修改对象头8个字节的地址来修改虚函数表,从而调用不同的虚函数。如 ((void **)(&b))[0] = ((void **)(&c))[0]就是把b的虚函数表修改成c的虚函数表了,调用的是c的方法

  • this指针其实是底层隐藏的函数
成员方法指针?
  • 函数指针
  • c++ 成员函数指针
  • 普通方法为什么不能存储成员方法地址?因为它有默认的this指针
dynamic_cast动态类型转换
  • 将基类的地址转换成其派生类的地址
  • dynamic_cast是运行期的行为
  • dynamic_cast与虚函数表是有关系的
虚析构函数

普通成员方法是跟着类走的,为了让其跟着对象走,就要设置成virtual

  • 规范析构顺序,使用虚析构函数
纯虚函数(抽象类)
  • virtual void run()=0,修饰之后必须在派生类中重写!
  • C++实现优先队列例子:用堆和队列分别实现
  • 请实现一个可以自定义哈希函数的哈希表类:哈希函数包括函数、函数对象、Lambda表达式
  • 扩容哈希表
# 知识强归纳 auto关键字
  • 在c语言中,用来说明局部的自动变量,当前变量的生存周期是编译器自动决定的,定义它的时候就产生了,出作用域的时候就回收了。(和局部变量一样)
  • c++11中, 使用auto方便遍历容器,在编译期就确定了,与sv中的foreach是一样的功能,typeid(x).name()可以查看属性;
  • auto不能作为函数参数;不能作为模板参数;不能定义数组;不能用于非静态成员属性;
constexpr编译期常量
  • const 运行期常量

  • 与const关键字的区别:一个是编译期常量,一个是运行期常量。

  • 修饰全局函数、修饰普通函数、修饰构造函数

  • 在模板中也会与decltype来搭配使用

NULL和nullptr
  • NULL在C与C++中的区别
  • C++中的NULL所带来的的歧义:func(int),func(int *)
  • nullptr是空指针更准确、无歧义的语义表达
右值引用

值类别

  • C++左右值(引用)示例
  • C++引用绑定顺序
  1. 左值与右值
    到了代码的下一行,是否可以通过单一变量访问到值:能访问到就是左值,不能就是右值、(判断不严谨,但是可以用)
  2. 左值引用与右值引用
  3. 非const变量绑定引用优先顺序
  4. const变量绑定优先顺序
  • 左值引用,使用T&,只能绑定左值
  • 右值引用,使用T&&,只能绑定右值
  • 常量左值,使用const T&,既可以绑定左值又可以绑定右值
  • 已命名的右值引用,编译器会认为是个左值
  • 编译器有返回值优化,但不要过于依赖
引用转换 forward与move:强制调用想调用的函数类型
  • 完美转换,主要在模板当中使用,
  • forward就是一个类型转换,
  • move主要把一个左值或者右值转换成一个右值

左绑左,右绑右;不管咋,先看const;const Type t可以绑定所有类型数据

move constructor 移动构造
  • 把一个右值转换成左值
  • 在战场上,死兵的武器直接抢过来使用
# 三、泛型编程:模板

模板在编译期完成完整的运算,其他的一般在运行期。
程序 = 算法 + 数据结构

数据结构: 能够存储任意类型
算法:能够存储 *** 作存储任意类型数据的数据结构

面向过程编程:用模板实现函数过程
面向对象编程:用模板实现类

模板文件在编译阶段就干掉了,必须写在头文件中!

返回值后置

  • 自己可以实现一个vector练习练习
  • C++使用move实现vector
引用类型推导

T&&传入引用类型,
引用折叠:出现偶数个&叫右值引用,出现奇数个叫左值引用。

特化模板

设计一个可以解析变参列表的工具,例如使用变参列表中的第二个类型定义一个变量。

# 其他内容 异常 C++线程简单使用

std::thread

bind简单使用 function 线程池、线程安全的日志打印功能 设计模式:单例模式 智能指针模板 lambda 后记 :低调思考
  • 企业不欠你的,不要带有学生思维意识,一年四季都有实习,随时准备一份简历
  • 大量的投递简历,填写自己真实的简历,都能获得大量的面试机会,撩要大胆,“渣男”思维
  • 自信是需要建立的,从小公司开始积累经验和面试机会,要有责任感,不要逃违约金。
  • 简历:留联系方式、在学校后面可以做特殊标记,减少废话(自我评价没用、年龄不要写、党员、籍贯没用)、个人技能一定要展开来写;多写客观因素、少主观因素;如果要证明c++这一块,可以写实现过stl中的某些东西,掌握了哪些知识点,算法数据结构、网络编程:掌握哪些数据结构,掌握哪些 排序算法,高级数据结构掌握到什么程度,比如了解红黑树呢还是实现红黑树?
  • 实现过linux下的某些命令,比如ls、cp、cat、find,自己实现pwd等命令;
  • 项目经历,是为了证明你在某些技能上是擅长的,不要写的浮夸
  • 要证明自己是想做技术的,对技术是热爱的,态度大于能力,以严谨的态度面对技术
  • 大公司造轮子,小公司用轮子
  • 面经的知识在于背,不在于会,不要只盯于c++开发:后端、后端、服务器、c++软件开发。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5115093.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-17
下一篇 2022-11-17

发表评论

登录后才能评论

评论列表(0条)

保存