C++ 基础
C++
C++ 纯编译型语言,支持面向对象。
兼容 C
基础兼容性
- 基本数据类型
| 变量 | bool | char | short | int | void* | long | float | double |
|---|---|---|---|---|---|---|---|---|
| 内存 | 1 | 1 | 2 | 4 | 4 | 4/8 | 4 | 8 |
// C++ 存在基本的 bool 类型,不像 C,啥都没有
// 这两条语句是基本相似的
if(1){ cout<<true; }
if((bool)1){ cout<<true; }
/*
* C/C++ bool 自动转化规则
* 0/NULL --> false
* number/(void*) --> true
*/
cin/cout 本身是一种流对象。
// 流对象支持指针或标准变量
cout<<"hello world"<<"!\n"<<endl;
cin<<b;
- 变量控制
#define //宏变量
static int a; //静态变量
extern int b; //引入外部变量
register int c; //寄存器变量
auto int e; //默认块变量
const int d; //只读变量
volatile int f; //对变量施加内存屏障,访问控制不走任何缓存
restrict int g; //当前对象只有这一个引用可访问,其他所有引用皆无效
mutable //存储类,对象相关
thread_local //存储类,线程相关
- 运算符
/*
1. 算术运算符
2. 关系运算符
3. 逻辑运算符 ! && || 逻辑运算会自动短路
4. 位运算符
5. 赋值运算符
6. 其他运算符
new : . >> << 等新增运算符。
*/
- 流程控制
while(){}
for(){} // for 第一次也会执行判断
do{}while();
switch(){case: break; case: continue;}
if(){}
if(){}else{}
Exp ? Exp : Exp ; //简化条件公式
- 函数定义
// 函数定义没啥好说的
void def(int a,int b){
count<<a<<b<<endl;
}
// 函数参数默认值,必须满足最右参数默认原则
void def(int a,int b=1,int c=2){
cout<<a<,b<<c<<a+b+c<<endl;
}
// def(0) def(0,1) def(0,1,2) 都可调用原始方法
// Lambda 函数表达式,这个语法糖好他妈丑
[capture](params)->{}
// 示例
[](int x,int y)->{return x+y;}
// 内联函数,仅在最终需要时展开执行
inline int show(int a){
return a*10;
}
// lambda inline 函数尽量只保留简单功能,逻辑不宜过于复杂
- 数据结构
// 数组
int a[10][10];
// 结构体
typedef struct List{
//...
}list;
// 位域结构体
typedef struct Step{
//...
}step;
// 共用体
typedef union Buffer{
//...
}buffer;
// 枚举
// 可直接输出,不可直接输入,因为枚举值是标识符常量
typedef enum Socre{
//...
}score;
特性兼容性
- 函数传参
// 值传递,copy副本
// 无法修改原始参数
void show(int val){
cout<<val++<<endl;
}
// 址传递,地址副本
// 可修改原始指针空间的值,以及指针
void show(int* val){
cout<<(*val)++<<endl;
}
// 引用传递,引用副本
// 可修改原始参数
void show(int& val){
cout<<val++<<endl;
}
- string
// C++ 字符串类
#include<cstring>
string str = "hello world";
// 字符串长度
int len = str.size();
cout<<"hello"<<" world"<<endl;
string str = str.substr(0,str.size());
str = str +str;
string a = "abc";
string b = "adc";
// 比较两个 string 对象时可用,基本 逻辑运算符
cout<<(a == b)<<endl; // 1 0
// 比较字符串对象与字符串时
cout<<a.compare("abc")<<endl;
- 内置库
// 相当于stdlib.h
#include<iostream>
// 数学方法函数
#include<cmath>
// 时间函数相关
#include<ctime>
// 不知道什么库
#include<cstdlib>
// 10位时间戳
cout<<time(NULL);
// 设置随机种子为当前 10位时间戳
srand((unsigned)time(NULL));
cout<<rand();
floor(3.6); -> int 3;
floor(-3.6); -> int -4;
ceil(3.6); -> int 4;
ceil(-3.6); -> int -3;
round(); // 精度
log(); // ln()
log10(); // log10
- IO
# include<iostream>
// 标准输出流,默认屏幕
cout<<"hello world"<<endl;
int a,b;
// 标准输入流,一次可执行多个
cin>>a>>b;
// 标准错误流,默认屏幕,会立即输出到屏幕
cerr<<"error"<<endl;
// 标准日志流,默认屏幕,存在缓冲区,缓冲区满了则刷新一次
clog<<"log"
// C++ 标准文件库,可以直接用 C 的标准文件库
#include<fstream>
- 指针与引用
/*
C 中的变量地址,可以拿出来,也可以利用地址强制指针化
C++ 中的变量地址,仅是可读的,但是拿不出来,更安全,但却少太多灵活性
*/
// C
int i = 100;
int ad = &i; // 这里可以直接取到变量的实际内存地址
// C++
int i = 100;
int ad = &i; // C++ 把这一步阉割了,&i 是可读的,但无法赋值于其他变量
// C++ 引用,别名
int i = 100;
int& j = i; // 此时 i j 仅代表一个变量,别名系统
int* p = &j; // i j 都可以取到指定的地址
- 异常处理
throw try-catch。
C++ 异常处理与 Java 非常相似。
https://www.cnblogs.com/MrYuan/p/4800257.html
// 异常头文件
#include<exception>
// try-catch 语句块
try{
if(true){
// 主动抛异常
throw 10;
}
// 捕获异常
}catch(int e){
cout<<i<<endl;
}
cout<<"hello world"<<endl;
// 自定义异常类型
class MyException:public exception{
virtual const char* what() const throw(){
return "MyException pass!";
}
}myexception; // 别名? c++ 搞得好乱
- 内存管理
int* p = NULL;
// C++ new-delete 内存管瘤
p = new int;
delete p;
// C malloc-free 内存管理
p = (int*)malloc(sizeof(int));
free(p);
// C++ new 申请一个对象空间,delete 释放一个对象空间
// C malloc 申请指定大小的空间,free 释放指针指向的空间
- 命名空间
C++ namespace 搞的有点垃圾。不如 Java 灵活。
// 自定义命名空间
namespace first{
void show(){
cout<<"first-show"<<endl;
}
}
// 使用 first.show() 方法
first::show()
// 加载命名空间,内部成员可直接使用,必须满足过程式结构
using namespace first;
// 可直接使用
show();
// 命名空间可嵌套定义,感觉作用不大
namespace second{
namespace sec{
int i = 100;
}
}
// 使用嵌套内部成员
second::sec::i;
- 模板成员
C++ 模板系列,就是 Java 的泛型。
C++ 泛型类双边必须都存在类型的定义,Java仅需要一边的。
// 泛型-函数
template <typename T> void show(T param){
cout<<param<<endl;
}
// 泛型-类
template <class T> class Exp{
T p;
public:
show(){
cout<<this->p<<endl;
}
}
// 使用泛型类
Exp<int>(1000).show();
Exp<int> p = Exp<int>(1000);
p.show();
- 指针使用
| $关键点$ | $解决方法$ |
|---|---|
| 指针定义 | 指针定义完成后,指向随机栈地址;需初始化null |
| 指针释放 | 除非还存在指向这片内存的指针,否则必须释放堆内存 |
| 内存 | 任何地方,堆内存只能主动申请,主动释放 |
| 内存指针 | 尽量不要多指针指向同一片内存,易出现异常 |
| 内存申请 | 某些场景下,需判断内存是否申请成功 |
| 内存释放 | 内存被释放后,指针依然可强制访问,需设指针为null |
| 函数参数 | 某些场景下,参数需要判断null |
| 函数返回 | 函数仅能返回主动申请内存的指针,局部变量值 |
| 内存嵌套 | 嵌套的结构只能从最内层向外层递归释放 |
| 内存数组 | 数组内使用堆内存还好,主要是小心下标越界问题 |
| 内存结构体 | 内部存在递归关系时,需要谨慎使用堆内存 |
面向对象
基础特性
- 类特性
class Exp{
int x;
int y;
// 静态,类级别变量,但依然受限于权限控制符
static int sta;
// 只读,初始化对象,或定义时即完成初始化
const int con = 100;
// 引用,初始化对象时,或定义时即完成初始化
int &y = x;
// this 可访问对象级别的所有成员
// this 无法访问类级别成员,static 静态成员 Exp.sta sta 即可访问
public:
// 预定义方法,参数定义有两种
int show(int x,int y);
show(int);
}; // class 结尾必须加 ;用以结束语句块
// 实现预定义的具体方法
Exp::show(int x,int y){
return x+y;
}
Exp::show(int param){
cout<<param<<endl;
}
/*
C++ 继承特性,private成员无法被继承,支持多重继承
public 继承父类 public->public,protected->protected
protected 继承父类 public/protected -> protected
private 继承父类 public/protected -> private
vittual 虚拟继承 What Fuck!
*/
- 成员特性
// 成员访问控制
class Exp{
public:
// 类-友元,子类,类外部
protected:
// 类-友元,子类
private:
// 类-友元
};
// 默认成员访问控制
class Exp{
// 所有成员默认 private
// 成员变量,默认私有
int x;
// 成员函数,默认私有
void show(){
cout<<"hello world"<<endl;
}
};
- 友元特性
// 友元,单向特性,拥有当前类的所有访问权限
class Exp{
int x;
// 此处申明指定类, 为本类的友元类
friend class demo;
// 此处申明指定函数,为本类的友元函数
friend void show(Exp);
}
// 友元类
class Demo{...}
// 友元方法
void show(Exp exp){
// 可直接访问私有成员
cout<<exp.x<<endl;
}
- 构造特性
class Exp{
int x;
public:
// 构造函数,创建对象时执行
Exp(int x){
this->x = x;
}
// 基于重载特性,深拷贝函数
Exp(const Exp obj){
this->x = obj.x;
}
// 析构函数
~Exp(){
// 释放对象内存时执行
}
/*
类继承时
构造函数:父类执行,子类再执行
析构函数:子类执行,父类再执行
*/
}
- 重载特性
// 重载,函数同名但参数不同,则视为不同函数
class Exp{
int x;
public:
Exp(int x){
this->x = x;
}
// C++ 支持,函数重名,
void show(){
cout<<"hello world"<<endl;
}
void show(int params){
cout<<params<<ednl;
}
// 另一种,运算符重载 =,赋予运算符特殊功能
Exp operator=(const Box& b){
//...
return null;
}
}
- 覆盖特性
// 子类可覆盖父类中同名成员(包括变量,函数)
class Exp{
public:
void show(){
cout<<"Class Exp"<<endl;
}
};
class Demo:public Exp{
public:
void show(){
cout<<"Class Demo"<<endl;
}
};
Exp().show();
Demo().show();
- 对象特性
// 结构体方式创建对象,不推荐使用
Exp exp(1,2,3); // 默认内存管理
// 标准对象创建方式,非堆内存对象,推荐使用
Exp exp = Exp(1,2,3); // 默认内存管理
// 标准对象创建方式,堆内存对象,推荐使用
Exp* exp = new Exp(1,2,3); // 主动内存管理,new delete 管理对象内存
// 对象引用复制
Exp& ex = exp;
// 对象指针复制,不推荐使用,多指针指向一个对象,内存管理非常麻烦
Exp* = &exp;
// 标准对象访问模式
exp.show();
// 指针对象访问模型
exp->show();
// 快捷方式
Exp(1,2,3).show();
new Exp(1,2,3)->show();
抽象特性
- 面向对象设计差异
| C++ | Java | |
|---|---|---|
| 类 | static控制 |
static控制 |
| 权限 | 3P原则,友元 | 3P原则 |
| 构造 | 构造析构,深拷贝 | 构造,GC回收,深拷贝,clone接口 |
| 继承 | n,3P原则,都成为子类的成员 | 1,public,子类与父类严格区分 |
| 覆盖 | 子类可覆盖父类的变量、函数 | 子类可覆盖父类的函数 |
| 重载 | 重载函数,运算符重载 | 重载函数 |
| 对象 | 引用、指针,可快捷化 | 引用,可快捷化 |
- 抽象设计
- 抽象类,存在一个或以上的
virtual所修饰的抽象方法。 - 接口,某个抽象类中只有
virtual所修饰的抽象方法。 - 抽象类、接口,没有严格的设计区分,需自行设计。
- 抽象类、接口,都不能直接实例化,必须由实现类实现抽象方法后才可使用。
class Exp{
public:
// 纯虚函数,就是Java中的抽象方法
virtual void show() = 0;
};
class Demo:public Exp{
public:
// 子类实现父类的抽象方法
void show(){
cout<<"hello world"<<endl;
}
};
// C++ 的抽象类:存在一个以上的纯虚函数
// C++ 的接口类:内部仅存在纯虚函数
// C++ 抽象系列与 Java 系列没什么差别
高级特性
容器特性
- 容器本身是一种数据结构,内部数据类型自定义。
- 注意一下容器迭代器,以及本身特性。
- vector
#include<vector>
// 本质上就是一个数组,但支持动态扩容
// 开始时,申请一块内存,扩容时释放原内存,申请新内存即可
vector<int> arr = {1,2,3,4,5,6};
vector<int> arr(10,0);
cout<<arr[0]<<arr[5]<<endl;
arr.push_back(10);
arr.pop_back();
arr.size();
stack<int> sta;
sta.push(1);
sta.pop();
unordered_set<string> set;
set.insert("hello world!");
- deque
#include<deque>
// 本质上就是一个双端队列,但其队列头、尾的插入删除非常块。
- list
#include<list>
// 双向链表,插入、删除快,随机访问比较慢。
- map
#include<map>
// 映射集合 key:value,内部自建一个红黑树
- set
#include<set>
// 集合,不允许重复,内部自建红黑树
多线程-锁

浙公网安备 33010602011771号