C+ +概述
1、嵌入式中为什么需要C+ +?
2、C+ +就业方向
3、C+ +面向对象特点(面向过程VS 面向对象)
4、C++标准(C++98, C++11, C++14, C++17, C++20)
5、C++编译器(vs微软VS g++) (命名空间: vs命名名字:成员) g++
6、命名空间(作用(命名冲突:全局变量、函数)、使用注意事项、义使用命名)
7、C++ 输入输出(printf )
8、C++关键字register. using、 auto (类型推导:高效编程) const、 constexpr
9、C++引用(作用、函数形参、返回值、左值、右值引用)指针VS引用
10、C+ +分配空间: new、 delete
11、C+ +对函数的升级(函数重载,内联函数)
12、C+ +类型升级struct- class(类,成员,成员变量,方法(函数))
13、string类
C++在嵌入式开发中地位及应用领域:上层应用软件(c/c++/java/object c/php、脚本语言:python)
中间框架(运行库)(sqlite3、网络线程库、opengl、opencv、tensorflow、caffer框架)
系统:Linux Android (C/汇编/脚本) Linux内核
底层硬件:ARM 人工智能芯片(fpga) — 汇编/硬件编程语言
学习C++的意义:C++:c with class:对C语言开发的帮助 面向结构 VS 面向对象
掌握C/C++ :帮助快速学习其他语言
面向对象的思想帮助系统的设计及架构
面向结构 VS 面向对象:
面向结构编程:
优点:能够直接访问硬件(指针)、运行效率、移植性
缺点:具体任务(具体且简单的业务逻辑)(复用性(功能复用)、维护性(准确定位)、扩展性(需求不断变化))
面向对象:
优点:复用性(继承)、维护性(封装)、扩展性(多态)
系统任务(复杂的业务逻辑)
缺点:降低了语言本身的性能
c++对c的加强:
1.命名空间
2.输入与输出
3.实用性加强
4.引用
5.动态分配内存(new、delete)
命名空间的加强:
为什么要引入命名空间的概念:为了解决合作开发时的命名冲突问题,C++ 引入了命名空间(Namespace)的概念。命名空间将全局作用域分成不同的部分、不同命名空间中的标识符可以同名而不会发生冲突、命名空间可以相互嵌套、全局作用域也叫默认命名空间
命名空间的定义:namespace 是C++中的关键字,用来定义一个命名空间,语法格式为:
namespace name
{
变量
函数
类
}
name是命名空间的名字,它里面可以包含变量、函数、类、typedef、#define 等,最后由{ }包围 、命名空间的定义可以嵌套
namespace NameSpaceB
{
int a = 1;
namespace NameSpaceC { struct Teacher { char name[10]; int age; }; }
}
命名空间的使用:1.使用域解析符::
::是一个新符号,称为域解析操作符,在C++中用来指明要使用的命名空间。
NameSpaceA::a = 10; // 使用命名空间 NameSpaceA中的变量a
2.使用using声明
// 在这里用using声明了 NameSpaceA::a, 它的意思是在声明以后的程序中如果出现
// 未指明命名空间的a,就使用NameSpaceA命名空间里的a
// 如果要使用NameSpaceB命名空间中的a,则仍需要使用这样的方式 NameSpaceB::a;
using NameSpaceA::a;
a = 20; // 使用命名空间NameSpaceA中的a
NameSpaceB::a = 30; // 使用命名空间NameSpaceB中的a
// using 声明不仅可以针对命名空间中的变量或者函数,还可以对整个命名空间进行声明
// 这样的方式声明命名空间以后,在后面使用未指定具体命名空间的变量或者函数产生命名冲突的时候
// 默认使用 NameSpaceB中的变量和函数
using namespace NameSpaceB;
a = 10;
printf ("%d\n", NameSpaceB::a);
命名空间的注意事项:1、源文件不能访问其他源文件的命名空间(命名空间中存在定义)
(即时放在头文件里,然后包含之后都无法访问)
2、名字空间名称相同,成员名字不同,那么他们会自动合并为一个名字空
间,可以理解为追加
3、字空间名称相同,成员名称相同。那么程序会在调试过程的link时报错。因
为连接器会检测到重复定义的变量。(extern)
一个c++程序中需要注意:1、命名空间的作用范围
2、使用规范:将 std 直接声明在所有函数外部,这样虽然使用方便,但
在中大型项目开发中是不被推荐的,这样做增加了命名冲突的风险,推
荐在函数内部声明 std。
输入与输出的加强:c++的I/O发生在流中,流是字节序列
I/O库头文件: 该文件定义了cin、cout、cerr和clog对象
该文件通过所谓的参数化的流操纵器,来声明执行标准化
有用的服务
该文件为用户控制的文件处理声明服务.
标准输出流cout:预定义的对象 cout 是 iostream 类的一个实例
标准输入流 cin:预定义的对象 cin 是 iostream 类的一个实例
标准错误流 cerr:cerr 是 iostream 类的一个实例、cerr 对象是非缓冲的,且每个流插入到 cerr 都会
立即输出。
标准日志流 clog:clog 是 iostream 类的一个实例、clog 对象是缓冲的
实用性加强:
for语句:可以在括号里直接定义并初始化变量
foreach用法
register关键字的变化:register关键字请求“编译器”将局部变量存储于寄存器中
C语言中无法取得register变量地址
在C++中依然支持register关键字
1、C++编译器有自己的优化方式,不使用register也可能做优化
2、C++中可以取得register变量的地址
C++编译器发现程序中需要取register变量的地址时,register对
变量的声明变得无效。
bool类型关键字:C++在C语言的基本类型系统之上增加了bool
C++中的bool可取的值只有true和false
三目运算符的增强:1)C语言返回变量的值
C++语言是返回变量本身
C语言中的三目运算符返回的是变量值,不能作为左值使用
C++中的三目运算符可直接返回变量本身,因此可以出现在程序的
任何地方
2)注意:三目运算符可能返回的值中如果有一个是常量值则不能
作为左值使用
(a < b ? 1 : b )= 30;
3)C语言如何支持类似C++的特性呢?
当左值的条件:要有内存空间;
C++编译器帮助程序员取了一个地址而已.
auto关键字:C语言auto关键字主要强调存储周期
C++中的auto关键字的作用自动推断变量的类型,通过变量的初始值或者表
达式中参与运算的数据类型来推断变量的类型
auto定义的变量必须初始化
使用using定义别名(替代typedef):using func_t = void (*)(int, int);
引用:为变量的别名,定义的时候必须初始化绑定一个指定对象,且中途不可更改绑定对象
使用注意事项:引用&初始化的时候,必须要与另外一个变量建立绑定关系。
一旦引用&与某一变量建立绑定关系,这个关系就不会再被改变,
作用:函数传参、返回值
const升级:C语言只读变量,C++常量
常引用:不能通过引用去修改绑定值
常量表达式constexpr:
作用:值不会改变并且在编译过程中就得到计算结果的表达
式
constexpr函数是指能用于常量表达式的函数
好处:是一种很强的约束,更好地保证程序的正确语义不被
破坏
编译器可以在编译期对constexpr的代码进行非常大的
优化,比如将用到的constexpr表达式都直接替换成最
终结果等。
相比宏来说,没有额外的开销,但更安全可靠。
指针和引用的区别:本质:引用只能绑定一次,指针可以绑定在任意的变量
内存分配:引用不占用内存空间(用户无法操作),指针占用内存空间(error)!!
!!!引用不是新的数据类型,
级数:指针可以多级指针,引用只能一级(error)!!!右值引用
使用效率:效率,安全性,推荐使用引用
左值、右值、左值引用、右值引用:可以通过&运算符获取地址的,就是左值;若否就是右值
左引用绑定左值
右引用绑定右值
动态内存分配(new、delete):
new、delete使用——二维数组、数组指针等分配
new、delete VS malloc free:
new关键字是c++的一部分,malloc是有c库提供的函数
new以具体类型为单位进行内存分配,malloc只能以字节为单位进行内存分配
new在申请单个类型变量是课进行初始化,malloc不具备内存初始化的特性
c++对c的函数扩展:
内联函数:inline是由编译决定,使用inline关键字只是申请编译器;
限制:内联函数中不可含有循环;
内联函数中不可能含有静态变量;
内联函数不可为递归函数;
内联函数中不可含有错误处理。
选择:只将规模很小(一般5个语句一下)而使用频繁的函数声明为内联函数。
注意事项:内联函数的定义必须出现在内联函数第一次调用之前;
默认参数:C++中可以在函数声明时为参数提供一个默认值,
当函数调用时没有指定这个参数的值,编译器会自动用默认值代替
规则:只有参数列表后面部分的参数才可以提供默认参数值
一旦在一个函数调用中开始使用默认参数值,那么这个参数后的所有参数都必须使用默
函数重载:
概念:用同一个函数名定义不同的函数,当函数名和不同的参数搭配时函数的含义不同
函数重载判断标准: 参数个数不同,参数类型不同,参数顺序不同
函数返回值不是函数重载的判断标准
调用函数重载的准则:将所有同名函数作为候选者
尝试寻找可行的候选函数:
1 )精确匹配实参
2) 通过默认参数能够匹配实参
3) 通过默认类型转换匹配实参
匹配失败:
1) 最终寻找到的可行候选函数不唯一,则出现二义性,
编译失败。
2) 无法匹配所有候选者,函数未定义,编译失败。
函数重载的注意事项:重载函数在本质上是相互独立的不同函数(静态链编)
重载函数的函数类型是不同的
函数返回值不能作为函数重载的依据
函数重载是由函数名和参数列表决定的。
函数重载与函数指针:当使用重载函数名对函数指针进行赋值时:
根据重载规则挑选与函数指针参数列表一致的候选者
严格匹配候选者的函数类型与函数指针的函数类型
struct结构体升级:
定义与使用
结构体内定义函数
权限修饰符:public、private—默认public权限
可继承
类的概念—class一种新的类型;定义的变量称为对象
默认private权限;
string类:
string类的构造函数
string s1;//默认构造函数,s1为空串
string s2(s1);//将s2初始化为s1的副本
string s3(“value”);//将s3初始化为一个字符串副本
string s4(n,‘c’);//将s4初始化为字符串’c’的n个副本
string类的字符操作
const char &operator[](int n)const;
const char &at(int n)const;
char &operator[](int n);
char &at(int n);
operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range异常,下标运算符[]不提供检查访问
int copy(char *s, int n, int pos = 0) const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目
string类的特性描述
int capacity()const; //返回当前容量(即string中不必增加内存即可存放的元素个数)
int max_size()const; //返回string对象中可存放的最大字符串的长度
int size()const; //返回当前字符串的大小
int length()const; //返回当前字符串的长度
bool empty()const; //当前字符串是否为空
void resize(int len,char c);//把字符串当前大小置为len,并用字符c填充不足的部分
string类的输入输出操作
string类重载运算符operator>>用于输入,同样重载运算符operator<<用于输出操作。
函数getline(istream &in,string &s);用于从输入流in中读取字符串到s中,以换行符’\n’分开
string类的赋值
string &operator=(const string &s);//把字符串s赋给当前字符串
string &assign(const char *s);//用c类型字符串s赋值
string &assign(const char *s,int n);//用c字符串s开始的n个字符赋值
string &assign(const string &s);//把字符串s赋给当前字符串
string &assign(int n,char c);//用n个字符c赋值给当前字符串
string &assign(const string &s,int start,int n);//把字符串s中从start开始的n个字符赋给当前字符串
string &assign(const_iterator first,const_itertor last);//把first和last迭代器之间的部分赋给字符串
string类的连接
string &operator+=(const string &s);//把字符串s连接到当前字符串的结尾
string &append(const char *s); //把c类型字符串s连接到当前字符串结尾
string &append(const char *s,int n);//把c类型字符串s的前n个字符连接到当前字符串结尾
string &append(const string &s); //同operator+=()
string &append(const string &s,int pos,int n);//把字符串s中从pos开始的n个字符连接到当前字符串的结尾
string &append(int n,char c); //在当前字符串结尾添加n个字符c
string &append(const_iterator first,const_iterator last);//把迭代器first和last之间的部分连接到当前字符串的结尾
string类的比较
bool operator==(const string &s1,const string &s2)const;//比较两个字符串是否相等
运算符">","<",">=","<=","!="均被重载用于字符串的比较;
int compare(const string &s) const;//比较当前字符串和s的大小
int compare(int pos, int n,const string &s)const;//比较当前字符串从pos开始的n个字符组成的字符串与s的大小
int compare(int pos, int n,const string &s,int pos2,int n2)const;//比较当前字符串从pos开始的n个字符组成的字符串与s中pos2开始的n2个字符组成的字符串的大小
int compare(const char *s) const;
int compare(int pos, int n,const char *s) const;
int compare(int pos, int n,const char *s, int pos2) const;
compare函数在>时返回1,<时返回-1,==时返回0
string类的子串
string substr(int pos = 0,int n = npos) const;//返回pos开始的n个字符组成的字符串
string类的交换
void swap(string &s2); //交换当前字符串与s2的值
string类的查找函数
int find(char c, int pos = 0) const;//从pos开始查找字符c在当前字符串的位置
int find(const char *s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
int find(const char *s, int pos, int n) const;//从pos开始查找字符串s中前n个字符在当前串中的位置
int find(const string &s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
//查找成功时返回所在位置,失败返回string::npos的值
int rfind(char c, int pos = npos) const;//从pos开始从后向前查找字符c在当前串中的位置
int rfind(const char *s, int pos = npos) const;
int rfind(const char *s, int pos, int n = npos) const;
int rfind(const string &s,int pos = npos) const;
//从pos开始从后向前查找字符串s中前n个字符组成的字符串在当前串中的位置,成功返回所在位置,失败时返回string::npos的值
int find_first_of(char c, int pos = 0) const;//从pos开始查找字符c第一次出现的位置
int find_first_of(const char *s, int pos = 0) const;
int find_first_of(const char *s, int pos, int n) const;
int find_first_of(const string &s,int pos = 0) const;
//从pos开始查找当前串中第一个在s的前n个字符组成的数组里的字符的位置。查找失败返回string::npos
int find_first_not_of(char c, int pos = 0) const;
int find_first_not_of(const char *s, int pos = 0) const;
int find_first_not_of(const char *s, int pos,int n) const;
int find_first_not_of(const string &s,int pos = 0) const;
//从当前串中查找第一个不在串s中的字符出现的位置,失败返回string::npos
int find_last_of(char c, int pos = npos) const;
int find_last_of(const char *s, int pos = npos) const;
int find_last_of(const char *s, int pos, int n = npos) const;
int find_last_of(const string &s,int pos = npos) const;
int find_last_not_of(char c, int pos = npos) const;
int find_last_not_of(const char *s, int pos = npos) const;
int find_last_not_of(const char *s, int pos, int n) const;
int find_last_not_of(const string &s,int pos = npos) const;
//find_last_of和find_last_not_of与find_first_of和find_first_not_of相似,只不过是从后向前查找
string类的替换函数
string &replace(int p0, int n0,const char *s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const char *s, int n);//删除p0开始的n0个字符,然后在p0处插入字符串s的前n个字符
string &replace(int p0, int n0,const string &s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const string &s, int pos, int n);//删除p0开始的n0个字符,然后在p0处插入串s中从pos开始的n个字符
string &replace(int p0, int n0,int n, char c);//删除p0开始的n0个字符,然后在p0处插入n个字符c
string &replace(iterator first0, iterator last0,const char *s);//把[first0,last0)之间的部分替换为字符串s
string &replace(iterator first0, iterator last0,const char *s, int n);//把[first0,last0)之间的部分替换为s的前n个字符
string &replace(iterator first0, iterator last0,const string &s);//把[first0,last0)之间的部分替换为串s
string &replace(iterator first0, iterator last0,int n, char c);//把[first0,last0)之间的部分替换为n个字符c
string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last);//把[first0,last0)之间的部分替换成[first,last)之间的字符串
string类的插入函数
string &insert(int p0, const char *s);
string &insert(int p0, const char *s, int n);
string &insert(int p0,const string &s);
string &insert(int p0,const string &s, int pos, int n);
//前4个函数在p0位置插入字符串s中pos开始的前n个字符
string &insert(int p0, int n, char c);//此函数在p0处插入n个字符c
iterator insert(iterator it, char c);//在it处插入字符c,返回插入后迭代器的位置
void insert(iterator it, const_iterator first, const_iterator last);//在it处插入[first,last)之间的字符
void insert(iterator it, int n, char c);//在it处插入n个字符c
string类的删除函数
iterator erase(iterator first, iterator last);//删除[first,last)之间的所有字符,返回删除后迭代器的位置
iterator erase(iterator it);//删除it指向的字符,返回删除后迭代器的位置
string &erase(int pos = 0, int n = npos);//删除pos开始的n个字符,返回修改后的字符串
string类的迭代器处理
string类提供了向前和向后遍历的迭代器iterator,迭代器提供了访问各个字符的语法,类似于指针操作,迭代器不检查范围。
用string::iterator或string::const_iterator声明迭代器变量,const_iterator不允许改变迭代的内容。常用迭代器函数有:
const_iterator begin()const;
iterator begin(); //返回string的起始位置
const_iterator end()const;
iterator end(); //返回string的最后一个字符后面的位置
const_iterator rbegin()const;
iterator rbegin(); //返回string的最后一个字符的位置
const_iterator rend()const;
iterator rend(); //返回string第一个字符位置的前面
rbegin和rend用于从后向前的迭代访问,通过设置迭代器string::reverse_iterator,string::const_reverse_iterator实现
vector类:STL容器–替代数组的使用
vector vt;
vt.reserve(100);
类型转换:
C语言的隐式转换和显示转换
C++的类型转换运算符
static_cast(expr):类似于C语言的强制转化,保证代码的安全性和正确性
可用于:相关类型转换;例如整型、实型
子类转父类
void *指针与其他类型指针之间的转换
不可用于:指针之间类型的转换
const_cast(expr):去除指针和引用的const属性;
使用该运算符转换意味着代码设计存在缺陷
dynamic_cast(expr):运行时类型识别和检查,用于父类子类之间的转换
reinterpret_cast(expr) :编译的过程中进行类型转换
reinterpret重新解释:处理无关类型的转换
特点:不安全,既不在编译器期也不在运行期进行检查,安
全性完全由程序员决定