一、c++新增特性
1.c++介绍
c++:c plus plus
c:更多的是面向过程,为了实现一个功能,如何通过一个过程来实现,注重的是算法
c++:更多的是面向对象,为了实现一个功能,如何构造一个对象模型来实现。
c和c++的关系:
①c++是向下兼容c的
②c++在c的基础上新增了很多新的特性、关键字、语法规则、设计思想
③c更多的是面向过程,c++更多的是面向对象
④面向对象也是通过面向过程来实现的
2.命名空间
作用:解决命名冲突
定义:
Namespace 命名空间名
{
变量定义;
函数定义;
类型名定义;
};
使用命名空间中的成员:
①命名空间名::变量名; (::——作用域运算符)
②Using namespace 命名空间名;变量名;//可以不用使用命名空间名直接调用变量
3.标准输入输出流
c中:
标准输入:键盘 scanf
标准输出:显示屏 printf
c++中:一切皆对象
标准输入流对象 cin
标准输出流对象 cout
4.引用
引用:就是变量的别名
作用:弱化指针的使用
定义:数据类型 &引用名 = 变量名;
引用与指针的区别:
①定义方式不同:
引用是已存在变量的别名,定义时需要在变量名前添加&符号,不用额外开辟空间。
指针是一个变量,存储了另一个变量的地址,定义时需要在变量名前添加*符号,需开辟一个四字节的空间存放变量地址。
②使用方法不同:
引用在使用时就像是变量的一个别名,可以直接使用原变量名来操作数据,无需使用*符号进行解引用。
指针需要使用*符号进行解引用获取存储在该地址上的数据。如 a = *ptr。
③初始化方式不同:
引用必须在定义时初始化,不能再指向其他变量,如 int &ref = a; a = b;这是错误的。
指针可以在定义后再进行初始化和指向其他地址,如 int *ptr = &a; ptr = &b;。
④类型不同:
引用是一个类型的别名,使用时需要与原变量类型相同,如 int &ref = a; double &dref = b;
指针是一个具有地址的变量,类型可以任意指定,如 int *ptr = &a; double *dptr = &b;。
总的来说,引用的使用方便,尤其适合在函数参数和返回值中使用,可以避免指针操作中的繁琐操作。而指针则具有更高的灵活性,能够直接通过指针实现对内存中数据的访问和操作。
应用场景
引用通常用作函数参数或返回值,在传递对象过程中避免不必要的复制开销。此外,引用还可以用于操作符重载和类成员函数。
指针通常用于动态内存分配、指针运算与数据结构等方面。
5.函数重载
①函数名相同(功能相似)
②参数不同(类型、个数)
③与返回值无关
注意:函数重载的原理:g++编译器会对函数名按照函数形参进行重命名
6.默认参数
7.c++调用c库
①制作c库
②让g++编译器不要对c库的函数重命名
extern “C” //告诉编译器这是外部的c的函数,按照c的方式编译
{
}
但是gcc编译器不认识extern “C”,所以需要进行if判断进行区分
#ifdef __cplusplus //g++中定义了这个宏,gcc中没有
extern “C” //告诉编译器这是外部的c的函数,按照c的方式编译
{
void fun1();
void fun2(int);
}
#else
void fun1();
void fun2(int);
#endif
8. 类和对象
类与对象的关系:
类是抽象的,对象是具体的;
类是对象的抽象,对象是类的具体实例。
构造函数有几种:
默认构造: 无参系统生成的、无参的自己写的、有参的并且所有参数都有默认值
普通构造: 有两个或者两个以上的参数,并且不是所有参数都有默认值
拷贝构造函数: 深拷贝、浅拷贝
转换构造函数: explicit修饰的
二、三大特性
1.封装
定义:把一类事物共同的属性和行为提取出来,提取的这个过程称为抽象;把提取出来的共性用类这种自定义的数据类型包起来,这个过程是封装。把该隐藏的隐藏起来,把暴露的暴露出来,通过访问权限来设置。
2.继承
继承作用:减少代码冗余,新写的类可以直接使用已经存在类的代码,提高开发效率,减少错误!提升代码的复用性!
使用继承的场景:当一个类是另外一个类的特殊版本的情况下,就可以使用继承!
继承的3种方式:private,public,protect
继承的格式:子类名:继承方式 父类名,继承方式 父类名{};
继承是如何继承:
子类要全部继承父类中的成员函数+数据成员!
友元函数是否会被继承:不是类的成员,是不会被继承的,它不具有传递性!
3.多态
分类:静态动态和动态多态
静态多态(静态绑定):在编译阶段,就知道执行哪一个函数体
动态多态(动态绑定):在运行阶段,才能知道要执行哪一个函数体
总结动态多态的实现条件:
- 一个父类,多个子类(继承关系)
- 父类中有虚函数,子类要重写父类的虚函数
- 要使用父类的引用或者指针去操作子类对象,调用虚函数的时候。
三、关键字
1.static
static在c中:
①static修饰局部变量:延长局部变量的生命周期
②static修饰全局变量:限制全局变量的作用域
③static修饰函数:限制了作用域
static修饰的变量,在编译阶段就已经存在了。
1.1static修饰类的数据成员
如何初始化:
数据类型 类名::变量名=初始值;
如何访问:
通过对象的方式去访问: 对象名.变量名;
通过类的方式去访问: 类名::变量名;
结论:
①类的静态的数据成员要类内做声明,类外做初始化。
②类的静态的数据成员属于类,不属于具体的某一个对象;但是所有对象都可以访问。
③类的静态的数据成员没有对象,也可以访问。
1.2 static修饰类的成员函数
①类的静态的成员函数中是没有this指针的,因为类的静态的成员函数没有对象也是能使用的!this存在没有任何的意义!
②类的静态的成员函数是不能访问类的非静态的成员的!
③类的非静态的成员函数是可以访问类的静态的成员!
④类的静态的成员函数的访问:对象的方式和类的方式都是ok的!
2.const
const的作用:
const int a = 100; //a的值不可以修改,此时a相当于常量
int b = 10;
const int *p = &b; // *p的值是不可以变化,p的指向是可以变化的
int * const p = &b;//p的指向是不可以变化的,但是地址中的值是可以修改的(*p)
2.1 const修饰类的数据成员
使用初始化列表的方式给const修饰的数据成员进行初始化
初始化列表的顺序并不会影响数据成员的赋值!
初始化列表只能出现在构造函数的地方。
当一个类中都const修饰的数据成员,并且这个类里面有多个构造函数,那么在每一个构造函数中都要使用初始化列表对const修饰的数据成员进行初始化。
2.2 const修饰类的成员函数
const修饰的成员函数中的this是不可以修改的, *this的值也是不可以修改的。
const修饰类的成员函数,本质上修饰的是隐藏的this指针。
const修饰的成员函数,只能访问类的成员,不能做修改。
const修饰的成员函数就是常函数!
注意:
const修饰的成员函数中不能访问非const修饰的成员函数;
非const修饰的成员函数中是可以访问const修饰的成员函数!
2.3 const修饰类的对象
const修饰的类对象只能调用const修饰的成员函数
2.4 mutable关键字
作用:解决const修饰类的成员函数不可以修改数据成员值的问题。但是尽量少用。
3.explicit
作用:防止构造函数在单参数的情况下进行隐式类型的转换
使用explicit 关键字修饰的构造函数,被称为转换构造函数。
4.inline
作用:修饰函数的,被inline关键字修饰的函数,被称为内联函数
什么是内联函数:
①短小的---3-5行
②逻辑简单 不能有for、while、if等语句存在
③频繁调用的
注意: 内联函数并不是你把函数用inline修饰,它就一定按内联的方式处理,这个是由编译器来判定的,它觉得这个函数能按内联处理,这个函数就是内联函数
5.final
作用: 修饰类以及类中的成员函数,final修饰的类不能被继承。
final修饰类的虚函数,此时虚函数在子类中不能被重写。
四、其他
1.异常处理
C++额外的新增了异常处理的机制:
异常定位:预测有可能出现异常的代码段 try{}
异常抛出:throw—异常就有各种各样的
异常捕获:catch(类型){ 对异常做出处理}
特点:
①跨级捕获-并处理异常
②C++中有提供专门的异常基类 exception
③C++中抛出的异常可以是类对象
2.转换函数
C语言中的类型转换有2种:
<1>隐式类型转换
<2>强制类型转换
C++中有额外的新增了4种类型转换函数模板。
3.智能指针
问题: 内存泄漏, new出来的空间没有使用delete去做释放!导致堆区的空间一直被占用。
解决: 有一种机制可以支持我们只要做new就可以了,释放不需要我们自己去做,让系统帮我们去做释放的工作。所以引入了智能指针。
本质也是模板,分为共享智能指针、弱型智能指针、独享智能指针。
4.单例设计模式
面向对象中的设计模式 23种
常用的:单例模式、工厂模式 (java)
单例模式:单个的实例 ,一个类只能有一个实例,即一个类只能创建一个对象
实现:
①构造函数私有化
②提供一个静态的成员函数获取唯一的对象
③提供一个静态的数据成员保存唯一的对象
分类
单例模式有两种,一种饿汉模式,一种是懒汉模式
懒汉模式:需要的时候才准备开辟空间
存在的问题:在多线程中,没法确保这个对象是否需要实例化
饿汉模式:提前申请好所需内存空间
存在的问题:有可能都没有使用到这个唯一的对象,就会造成资源的浪费
五、STL
STL:标准模板库,里面全部都是用模板去实现
STL中的6大组件是什么?
容器
算法
迭代器:面向对象版本中的指针 泛型指针
适配器
分配器
函数对象
1.vector
vector容器的结构:
动态数组: 数组的长度是不确定的
在内存中的地址是连续的,支持索引访问,也支持迭代器访问。
动态如何体现:
当容器的容量用尽的时候,自动的会去内存中找一块更大的连续的内存空间,然后把原来内存空间中的数据拷贝到新的内存中,把原来的内存给释放掉还给系统
2.list
结构: 双向链表
特点: 插入、删除的效率相对是高的;访问的效率相对vector来说是低的
使用:
#include <list>
3.map
底层结构: 红黑树---》平衡二叉树
结构体设计不同: 多了一个数据成员表示黑色还是红色。
Key-value的键值对
根据key可以找到对应的value数据,key与value是 一 一对应的关系
特点:
查找速度会很快
结论:
map容器会自动进行排序,排序的方式根据key值从小到大!
map容器中是不允许出现相同key的数据的!
代码如何表示map容器
map<key, value> key能否是char *类型:不要设计成char *
头文件 #include<map>