C++新增特性
更为严格的类型检查
新增变量引用
引用:给变量取别名,是一种数据类型
函数传参:值传参,地址传参,引用传参
int a = 123;
int &b = a;//给变量a取别名b
支持面向对象
类、对象、继承、多态、虚函数及RTTI(运行时类型识别)
新增泛型编程
目的:编写与类型无关的代码
模板:函数模板、类模板(STL标准模板库)
支持异常处理
支持函数及运算符重载
函数重载:在同一个作用域下可以定义多个同名且参数不同函数
支持命名空间
管理函数名、变量名、类
::作用域访问符
namespace name
{
//函数
//变量
//类
}
int main()
{
name::函数;
}
//or
using namespace name;
编译c++程序
编译过程:
预处理 .c->.i
编译 .i->.s
汇编 .s->.o
链接 .o->elf
编译器:
g++ 可执行文件
c与c++的兼容和差异
const:只能初始化,不能修改值
强制类型转换
(强转类型)表达式; //c
强转类型(表达式);//c++
引用类型
内联函数
inline 存储类型 数据类型 函数名 (参数列表)//节省运行时间,不能有复杂的控制语句
函数重载
函数模板
函数的默认参数
int add(int a=0,int b=0);
结构体
struct 结构体名
{
//成员变量
//成员函数
};
结构体名::成员变量//在结构体外定义结构体变量
权限
private://变为私有对象
protected://变为受保护对象
public://变为公共对象
内存模型
作用域
局部域
局部变量的作用域
全局域
全局变量的作用域
名字空间域
定义在命名空间的
类域
在类中的
链接性:描述了名称如何在各个单元中的共享
外部链接:名称可以在文件间共享
内部链接:名称仅在此文件中共享
动态内存
new/delete运算符
new:申请空间
delete:释放堆区空间
char *q = new char [20];
delete [] q;
int *p = new int;
delete p;
标准流,输入输出
using namespace std;
cin
cout
类和对象
opp的三大特征
封装:代码模块化
继承:代码重用
多态:接口重用
类
是一种自定义类型
是对一类事物共有属性和方法的抽象
是数据类型
不占用空间
类的定义
class 类名
{
//成员变量
//成员方法
}
对象
类名 对象名; //Stu stu01;
类名 *对象名 = new 类名; //Stu *stu02 = new Stu;
构造和析构顺序
由对象的生命周期决定
同生命周期,先构造的后析构,后构造的先析构
拷贝构造
用一个对象去初始化另一个对象的构造函数
static关键字
C:
修饰局部变量:修改局部变量的生命周期
修饰全局变量:修改全局变量的作用域
修饰函数:修改函数的作用域,只能在本文件调用
C++:
static修饰成员变量
不受对象的影响
不会在类初始化时初始化
在类的外部初始化
类的共享成员
不可使用this指针
static修饰成员函数
const关键字
C:
修饰变量:变量是只读变量,只能初始化,不能修改
修饰指针:
C++:
const成员变量:只能初始化,不能被修改(在类中使用构造方法的初始化列表进行初始化)//构造函数(参数) : const成员名(参数){}
const成员函数:不能通过const函数修改类对象
const对象:不能修改类对象
友员(类的朋友)(可以对类的私有成员直接访问)
友员函数:在类中对函数使用friend进行修饰,成为友元函数。
friend void setval(Demo &obj,int val);
void setval(Demo &obj,int val)
{
obj.val = val;
}
友元成员函数:一个类的成员函数是另一个类的友元函数
友元类:friend class 类名;//类B可以自由访问A的私有成员
不能继承,无交换性,无传递性
运算符重载
概念:给已有的运算符指定新的功能
目的:c++预定义的运算符只能对基本类型进行操作,想要让对象能够向基本类型操作,则需要运算符重载
语法:
返回值类型 operator 运算符 (参数)
{
函数体;
}
. ?: sizeof :: * 无法重载
->(特殊):重载返回该类型的指针,使用时实际上是p->m=10; // (p.operator->())->m = 10
[链接](http://www.tutorialspoint.com/cplusplus/class_member_access_operator_overloading.htm)
友元运算符重载
概念:运算符重载作为类的友元
class 类名
{
friend 返回值类型 operator 运算符 (参数);
}
成员运算符重载
概念:运算符重载作为类的成员
class 类名
{
返回值类型 operator 运算符 (参数);
}
返回值类型 类名::operator 运算符 (参数)
{
函数体;
}
输出流运算符重载
ostream &operator <<(ostream &os,const Demo &a)
{
os<<a.val;
return os;
}
函数模板
泛型编程
模板是泛型编程的基础
致力于编写与类型无关的代码
语法
template <class 参数名, class 参数名, ......>//类型形参列表
返回值类型 函数名(形参列表)
{
函数体
}
class/typename:指定参数类型
eg:
template <class T>
T add(T &a,T &b)
{
return a+b;
}
int main()
{
int a=10;
int b=20;
cout<<add(a,b)<<endl;
}
函数重载与函数模板
函数重载:功能相近且参数不同时选择函数重载
函数模板:功能相同且参数类型不同时选择函数模板
类模板
语法
template<class 形参名, ......>
class 类名
{
//成员
}
eg:
template <class T>
class Demo
{
private:
T val;
public:
Demo(T val) : val(val)
{
}
~Demo()
{
}
Demo<T>::setval(T val);
};
template<class T>//每次定义外部函数都需定义
void Demo<T>::setval(T val)
{
this->val = val;
}
int main()
{
Demo<int>(123);
}
模板默认参数
eg:
template <class T=int>//只可在类前默认
非类型模板参数
模板参数列表中可以定义确定类型的变量
eg:
template <class T,int len>//T类型实参,len非类型模板参数(只能为int,*,&)
类继承(代码复用)
概念
用已有的类来建立专用类的技术
已有的类叫父类
专用的类叫子类
语法
class 子类名 : 权限访问限定符 父类名1, 权限访问限定符 父类名2
{
}
权限访问限定符:public,private,protected
基类 派生类
public继承: public public
protected protected
private 只能通过基类的接口访问
protected继承: public protected
protected protected
private 只能通过基类的接口访问
private继承: public private
protected private
private 只能通过基类的接口访问
eg:
class Base
{
private:
int val;
public:
Base(int val=0) : val(val)
{}
~Base()
{}
void setval(int val)
{
this->val = val;
}
int getval()
{
return val;
}
};
class Inherit : public Base
{
private:
int newval;
public:
Inherit()
{}
~Inherit()
{}
};
class Inherit : public Base
{
private:
int newval;
public:
Inherit(val) : Base(val)//给父类的构造函数传参
{}
~Inherit()
{}
};
关系
is-a关系(继承关系)
has-a关系(组合关系)
is-implemented-a关系(实现一个类用到了另一个类)
is-like-a关系(多重继承)
多重继承
一个类有多个父类
eg:
class Man{};
class Wolf{};
class Wolfman : public Man,public Wolf
{};
可能引发二义性(父类都继承一个类,调用父类的方法可能会冲突)(使用虚基类和作用域解决)
多态(接口复用)
概念:
一个接口,由于个体差异有多种实现方法
虚函数
用virtual修饰成员函数,就是虚函数
eg:
class Demo
{
public:
vitrual void prt()
{}
};
限制:
非成员函数不能为虚函数
静态成员函数不能为虚函数
构造函数不能定义为虚函数,析构函数可以为虚函数
声明时用virtual修饰,定义时不需要修饰
基类的成员函数成为虚函数后,其派生类同名函数均为虚函数
eg:
class Base
{
public:
Base()
{}
~Base()
{}
void prt()
{}
};
class Inherit : public Base
{
public:
Inherit()
{}
~Inherit()
{}
void prt()
{}
};
void prtmsg(Base &obj)
{
obj.prt();//静态链接,在编译时由类型决定的函数,由于其形参为Base,故调用Base的prt
}
int main()
{
Base b;
Inherit i;
prtmsg(b);
prtmsg(i);
}
在定义基类成员函数时,使用virtual进行修饰则可以实现调用Inherit的prt(成为动态链接)
virtual void prt()
{}
重载:是在一个类中多态性的一种表现,是指在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型。
覆盖(重写):是指派生类函数覆盖基类函数。覆盖一个方法并对其重写,以达到不同的作用。重写的基类中被重写的函数必须有virtual修饰。
隐藏:是指派生类的函数屏蔽了与其同名的基类函数,注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。
动态联编
联编(链接)
就是将模块或者函数合并在一起生成可执行代码的处理过程。按照联编所进行的阶段不同,可分为两种不同的联编方法:静态联编和动态联编。
静态联编(静态链接)
是指在编译阶段就将函数实现和函数调用关联起来,因此静态联编也叫早绑定。
动态联编(动态链接)
是指在程序执行的时候才将函数实现和函数调用关联,因此也叫运行时绑定或者晚绑定。C++中一般情况下联编也是静态联编,但是一旦涉及到多态和虚拟函数就必须要使用动态联编了。
虚函数表的技术(实现多态)
基类的虚函数表登记的基类的虚函数,子类的虚函数表登记的是子类的虚函数;
定义对象时会给虚函数表的地址分配空间,即对象的指针指向的是虚函数表的首地址
虚继承
解决多重继承引发的二义性
class A : public virtual Base{};
class B : public virtual Base{};
class C : publc A, public B{};
虚析构
当基类析构函数为虚时,子类析构自动为虚
当子类对象结束时,会自动析构基类对象
Base *p = new Inherit;
delete p;
抽象类
纯虚函数
virtual 返回值类型 函数名 (参数列表)=0;//只声明不定义
限制
含有纯虚函数的类叫抽象类
只能是派生类的基类,不能有实例
不能有static成员
基类的纯虚接口需要在派生类中实现
限制构造函数(主要用于抽象类)
概念:构造函数的权限为protected/private
目的:限制构造对象
异常
概念:不正常,发送错误信息,处理异常(设计者检查错误并返回,使用者处理错误)
异常处理机制:try(检查)->throw(抛出)->catch(捕获)
异常处理格式
try
{
//检查语句
if(错误1)
{
throw 异常1;
}
else if(错误2)
{
throw 异常2;
}
...
}
catch(异常1)
{
处理异常1
}
catch(异常2)
{
处理异常2
}
...
标准异常(https://cplusplus.com/reference/stdexcept/)
exception(基类)
logic_error(逻辑错误) runtime_error(运行时出错)
... ...
eg:
int div(int a,int b)
{
if(b==0)//检错
{
throw invalid_argument("invalid argument");//抛出异常
}
else
{
return a/b;
}
}
int main()
{
int a = 1;
int b = 0;
try
{
cout << div() << endl;
}
catch(invalid_argument &iserr)//捕获异常
{
cout << iserr.what() <<endl;//处理
}
}
自定义异常
由已有的异常类派生
class 异常类 : public exception
{};
eg:
class Myexception : public exception
{
public:
Myexception(const char* what_arg) noexcept : what_arg(what_arg)
{}
~Myexception() noexcept
{}
const char* what() noexcept
{
return this->what_arg;
}
private:
const char *what_arg;
};
自定义
eg:
class Myexception
{
public:
Myexception(const char* what_arg) noexcept : what_arg(what_arg)
{}
~Myexception() noexcept
{}
const char *what() noexcept
{
return this->what_arg;
}
private:
const char *what_arg;
};
转换函数
目的:解决类型转换(自定义类型转换为基本类型)
转换函数
语法
operator 新类型名() const
{
实现转换的语句
}
标准转换函数
eg:
int *p = NULL;
char *q = NULL;
p = reinterpret_cast<int *>(q);//转换指针类型
const char *a = NULL;
char *b = NULL;
b = const_cast<char *>(a);//将const指针转换为普通指针
Base *base;
Inherit *iherit;
iherit = static_cast<Inherit*>(base);//将基类转换为派生类
Base01 *base01;
Inherit01 *inherit01;
inherit01 = dynamic_cast<Inherit01*>(base01);//将基类转换为派生类(有虚函数>
explicit关键字(阻止隐式类型转换)
eg:
class Demo
{
private:
int val;
public:
explicit Demo(int val=0):val(val)//防止隐式类型转换
{}
~Demo()
{}
int const getval()
{
return this->val;
}
};
int main()
{
Demo obj;
obj = Demo(123);//强制转换
obj = (Demo)123;
obj = 123;//隐式转换,系统默认匹配构造函数参数(无效)
cout << obj.getval() << endl;
}
自定义转换函数
eg:
class Demo
{
private:
int val;
public:
Demo(int val = 10) : val(val)
{}
~Demo()
{}
operator int()
{
return this->val;
}
};
智能指针
目的:只关心申请资源,不关心释放资源
本质:重载指针运算符(* ->)
shared_ptr:共享指针(多个指针指向同一片空间)
引入计数器:构造对象,计数器+1,析构对象,计数器-1
eg:
class Demo
{
private:
int val;
public:
void setval(int val)
{
this->val = val;
}
int getval()
{
return this->val;
}
};
int main()
{
shared_ptr<Demo>p(new Demo);
shared_ptr<Demo>q(p);
p->setval(666);
q->setval(888);
}
unique_ptr:独享指针
任意时刻只能有一个指针指向对象
eg:
unique_ptr<Demo>up(new Demo);
up->setval(999);
weak_prt:弱指针
配合共享指针判断对象是否存在
eg:
shared_ptr<Demo> p(new Demo);
weak_ptr<Demo> q = p;
p.reset();//Demo对象被析构
if(q.expired())//判断Demo对象是否存在,true为不存在,false为存在
{
cout << "Demo is not exist" << endl;
}
STL(标准模板库)(standard template library)
容器:特殊的数据结构,实现了数组、链表、队列等等,实质是模板类
算法:排序、遍历、查找等等,实质是模板函数
迭代器:一种复杂的指针,可以通过其读写容器中的对象,实质是运算符重载
空间配置器:容器的空间配置管理的模板类
配接器:用来修饰容器、仿函数、迭代器接口
仿函数:在类中重载 (),让对象模仿函数,调用实现功能
STL序列容器:vector、deque、list【https://www.jianshu.com/p/9ce095efeace】 STL常用接口实例:https://blog.csdn.net/zb1593496558/article/details/80987071
vector:相当于一个数组
list:相当于一个双向链表
deque:相当于双端队列