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,子类与父类严格区分
覆盖 子类可覆盖父类的变量、函数 子类可覆盖父类的函数
重载 重载函数,运算符重载 重载函数
对象 引用、指针,可快捷化 引用,可快捷化
  • 抽象设计
  1. 抽象类,存在一个或以上的 virtual所修饰的抽象方法。
  2. 接口,某个抽象类中只有 virtual 所修饰的抽象方法。
  3. 抽象类、接口,没有严格的设计区分,需自行设计。
  4. 抽象类、接口,都不能直接实例化,必须由实现类实现抽象方法后才可使用。
class Exp{
    public:
        // 纯虚函数,就是Java中的抽象方法
        virtual void show() = 0;
};
class Demo:public Exp{
    public:
        // 子类实现父类的抽象方法
        void show(){
            cout<<"hello world"<<endl;
        }
};
// C++ 的抽象类:存在一个以上的纯虚函数
// C++ 的接口类:内部仅存在纯虚函数
// C++ 抽象系列与 Java 系列没什么差别

高级特性

容器特性

  1. 容器本身是一种数据结构,内部数据类型自定义。
  2. 注意一下容器迭代器,以及本身特性。
  • 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>

// 集合,不允许重复,内部自建红黑树

多线程-锁


posted @ 2020-10-26 15:11  我去吃饭了  阅读(49)  评论(0)    收藏  举报