1、关键字的使用以及升级优化
1.1C与C++的区别
1.1.1都可以实现代码重用和模块化编程,但是面对对象的模块化更深,数据更封闭,也更安全!因为面向对象的封装性更强!
1.1.2面对对象的思维方式更加贴近于现实生活,更容易解决大型的复杂的业务逻辑
1.1.3从前期开发角度上来看,面对对象远比面向过程要复杂,但是从维护和扩展功能的角度上来看,面对对象远比面向过程要简单!
1.2、关键字
1.2.1 register(C)
register:提高程序运行效率:省去CPU从内存抓取数据的开销
语法作用:尽可能将变量保存在CPU内部寄存器中
使用注意事项:
只能修饰局部变量,不能修饰函数、全局变量
使用register修饰的变量,不能通过&获取该变量的地址;(有可能该变量保存在cpu内部寄存器中)
register修饰变量类型一定是CPU所能处理的数据类型;(有的cpu不支持浮点型运算)
什么时候用register修饰一个变量?(频繁访问的变量)
C++中优化:
优化内容:当对register变量取地址时,会将该变量重新保存到内存中;
搭配使用:
1.2.2volatile :防止编译器优化(将变量优化到寄存器中(寄存器存在边际效应))
使用场景:访问硬件时。所使用的全局变量;
一般定义寄存器变量:volatile register int index;
1.2.3 auto(C)
自动变量,离开作用域自动释放。
C++优化:
优化内容:auto 自动类型推导
1.2.2typedef (C):
语法作用:给数据类型重命名
工程应用:1、提高代码可读性;2、提高移植性;
用法:typedef 数据类型 重命名
存在一个问题:重命名函数指针时。可读性差;
typedef 重命名函数指针:
定义:typedef 数据类型 (*重命名)(int,int); \ typedef 数据类型 ( *) (int,int) 重命名;
(额外知识点:函数命名规则:解决的是函数功能的可读性,无法解决形参的可读性;)
C++优化:
typedef == using
1.2.3 const (C):
将一个变量变为只读变量;
工程应用作用:修饰函数形参,保存实参在函数执行过程中不能被修改;(编译阶段处理)
类比:constexpr(预编译阶段处理)
作用:值不会改变并且在编译过程中就得到计算结果的表达式;
constexpr函数是指能用于常量表达式的函数:
constexpr int new_sz() ireturn 42}; cosntexpr int foo = new_sz();(返回值一定是一个常量)。
好处:1、是一种很强的约束,更好地保证程序的正确语义不被破坏
2、编译器可以在编译期对constexpr的代码进行非常大的优化,比如将用到的constexpr表达式都直接替换成最终结果等。
3、相比宏(可替代宏)来说,没有额外的开销,但更安全可靠。
C++中const的作用?
1、const声明的变量是一个真正的变量(没有自己的存储空间),无法间接被改变;
2、
3、
4、
const和define的区别:
1、const可以指定数据类型;
2、所处时期不同:denfine处于预处理阶段(文本替换)、const处于编译器处理阶段;
3、const可以用于一些复杂的数据类型:(数组或者结构体)
const 离谁近谁就不能变:eg:
C++优化:
优化内容:const 修饰的变量是常量;
修饰指针函数与C相同;
1.2.5 bool
在C语言中需要添加头文件;在C++中可直接用。
两种结果:true / false
1.2.6 三目运算符
结果可以做左值;
1.2.7 while
升级了可以写逗号表达式: while(a > b, a < b)
2、类型的引用以及升级优化
2.1 引用 (C)
什么时候传地址,什么时候传值?
当修故实参变量值时,传实参变量的地址;(传实参变量的地址,即可以使用也可以修改实参变量的值)
当只使用不修改实参变量值时,传实参变量名;(传实参变量名,只能使用实参变量的值,不能修改)
注意事项:定义引用必须绑定变量;一旦绑定一个变量就不能绑定其他变量;
返回值:不要返回局部变量的地址或指针;加static可以延长使用周期(消除警告)
C++:
引用:解决就是函数指针传参和返回值问题;
引用就是给变量起别名,操作引用相当于在操作引用所绑定的变量
引用作为函数形参:解决传值和传地址问题;
常引用:只能使用不能修改其绑定的值
引用也可用于返回值:函数调用做返回值:修改返回的值;
C++11以后引用的作用被加强:(左值引用 右值引用)
左值:可以被修改的值可以叫做左值;(可以取地址的值可以作为左值)
右值:不可以被修改的值可以叫做右值;(不可以取地址的值可以作为右值)
左值引用:只能绑定左值; int &
右值引用:只能绑定右值; int && (对象移动)
面试题的扩充(C)(everyday 2.c)
3、new/delete
3.1 C语言中(malloc/free)
malloc原型: void * malloc(size_t size);
释放原型:void free (void *addr);
C++优化(new/delete)
new、delete:暂时理解为运算符;//malloc和free 是函数
new、delete:按照类型的个数为单位; //malloc、free:按照字节为单位分配
new、delete:可以初始化;//malloc、free:只能手动初始化
(关于初始化:最好手动初始化!!默认初始化都为0);
new、delete:如果分配失败会产生异常; //malloc、free:返回NULL;
new 对应底层调用的是 malloc;
delete 底层调用的是 free;
new malloc :频繁分配(小内存空间)内存会导致内存产生碎片,同时会增加(程序)开销;
(如何解决::池化技术:内存池!!)
关于多维数据分配:
1、规则的多维数组:int (*p)[5] = new int[2][5];
2、不规则的多维数据:int (**array);
NULL的定义:(C) #define NULL (void *) 0
(C++) nullptr;将指针设为空
可能会存在面试或笔试题:
4、函数
4.1 内联函数、内嵌函数
4.1.1 在 C 中
inline:修饰的函数为内联函数、内嵌函数;
空间(内存空间)、时间(编译时间、运行时间)
以时间换空间:消耗了更多编译/运行时间,换取占用更小的内存 (宏函数)
以空间换时间:占用更多的内存空间,换取运行时间
(inline 内联函数/内嵌函数 改变了函数调用的处理过(将函数体的内容内嵌到函数调用的地方)
内联的限制:1、内联函数中不可含有循环;
2、内联函数中不可能含有静态变量;
3、;内联函数不可为:递归函数;
4、内联函数中不可含有错误处理。
**注意事项**:内联函数的定义必须在第一次内联函数调用之前;
eg1:宏函数
处理阶段:预处理阶段
处理过程:傻瓜式替换 (没有空间分配) 不做语法检查!! 不安全
eg2:自定义函数
处理阶段:编译时检查语法、运行时函数进栈出栈;
处理过程:通过函数名找到函数的入口地址; 给形参分配空间; 传值; 执行函数体语句; 函数返回; 释放空间;
C++中:
inline:编译决定是否为内联处理
函数的默认参数:如果一个函数的参数为默认参数,那么它右边(后面)所有参数都必须为默认参数;
函数的占位符:预留函数接口
函数的重载:函数名命名的可读性问题;
函数重载的条件:1、函数形参的个数不同;
2、函数形参个数相同类型不同;
3、函数形参类型不同顺序不同;
函数的个数、类型、顺序不同!!!
注意事项:函数的返回值不能作为重载条件;函数默认参数会影响重载条件;
演示:(错误写法)
正确写法:
5、结构体
C++在C中的升级
1、可以省略在主函数中struct的声明;
2、可以在struct中定义函数;
3、可以对成员加入访问权限;
public(公有的):可以直接在外部访问;
private(私有的):只能在结构体内部使用或者内部函数直接访问,不能在外部访;
protected(保护的):只能在结构体内部使用或者函数内部直接访问,不能在外部访问;
访问权限好处:隐藏了数据(封装)
如何对private/protected成员设置值? 提供set/get方法;
**struct**的升级目的是为了引入**class**(类);
程序代码结构1: 在类里定义和实现方法:这些方法有可能会已inline处理
程序结构2: .h类的定义声明,不在类内去实现方法,编译器不会将方法用inline
struct 和 class 的区别
叫法1: struct 结构体class类struct定义的变量是结构体变量;class定义的变量称之为对象;
叫法2: struct/class :变量称之为属性或者是成员变量; 函数称之为方法;
默认访问权限: struct默认的是public ; class 默认的是 private
6、string类 (替代C中字符串的操作)
6.1 定义
6.2 获取属性
6.2.1
6.2.2 (长度)
1、获取字符串的大小;
2、有多少字符;
3、当前string的容量;它的值总是会比size()大一个或者多个;
4、当前环境最多可容纳多少字符; 注意:string可变长!!!!
6.3 遍历
6.3.1
第一个输出:[ ] 运算符: 越界不报错 不安全
第二个输出:at(int index) :如果访问越界, 会产生异常, 安全!!
eg:
6.3.2 迭代器遍历
6.4 连接
1、通过append 进行字符串的连接;
2、直接通过变量名进行连接;
3、通过迭代器进行连接;
6.5 赋值
6.6 比较
6.7 提取子串
s.substr(a,b); (a为你从子串哪里开始计数,b为需要提取多少)
6.8 交换
6.9 查找
6.9.1查找一个字符串里某个字符的位置
查找到返回该值下标,查不到返回其他
6.9.2
6.10 替换
6.11 插入
6.12 删除
注意事项:::最好不要在迭代器遍历中进行插入或者删除,因为这样会导致迭代器失效;
6.13 string类的迭代器处理
7、vector
一定要注意加载头文件#include <vector>
以后尽量都用vector 容器来定义数组
也可以定义很多类型
7.1 在vector 的末尾添加/删除数据
v.push_back(int n); //在末尾添加数据
v.pop_back(int n); // 在末尾删除数据
注意一定是在**末尾**
7.2 在中间插入或者删除
v.insert(位置,int n); //在中间某个位置插入一个数据
v.erase(位置,int n); //在中间删除某个数据
注意是在**中间**进行操作;
8、类型转换
8.1 在C语言中
1、隐式转换: char -- int -- double -- float -- long
eg: int num = 'a'; double b = num;
2、显式转换(强制类型转换):(type) 变量名
eg: char *ptr = (char *)malloc(sizeof(char *) * 100);
8.2 C++优化
C++为什么提出新的类型转换运算符?
C语言类型转换是个不安全转换(任意类型转化,不检查)
8.3 static_cast
1、可以转换::相关类型(int、float这些基本转换);父类与子类;void *与其他类型指针的转换
2、任意两个类型的指针之间转换不能用static_cast;
8.4 reinterpret_cast
C++中强制类型转换;可以达到任意类型转换,但是不检查错误;建议少用,不安全。
8. 5 const_cast(去掉const的属性)
1、允许非const赋值给const; 不允许const赋值给非const;(会改变const的值)
2、const_cast 只能去除指针或者引用的const属性;
8.6 d’ynamic_cast(多态)
与static_cast 用法大致相同;