对弈的C++学习笔记

时间:2023-03-09 04:27:42
对弈的C++学习笔记
2018-07-11上传
一:从C到C++
1.C++新类型 bool 判断真假 占用一个字节
     if(条件) 真1或者假 0
    bool 类型的取值 true false
 
    内存最小单位 字节
        ----> 新类型bool 取值(true false) 判断真假 一个字节
        -->想要省内存的方式---> 使用结构体 位域(<< >>)
2.引用
    直接传参数 形参改变了 实参不会变
    如果要用形参修改实参 指针或者引用(效率更高)
    int& pa=x//定义一个引用
    引用-->外号,昵称
2.1 用引用和用对象本身是一样的
2.2 定义的时候必须赋值,且不能重新赋值(相当于常量)
2.3 编译的时候不占内存
2.4 效率最高
    和指针的比较
                 函数传参 -->使用引用比指针效率更高 (将参数类型 定义为引用)
    引用          定义的时候赋初值 引用不能重新赋值 (常量) 编译的时候不占内存
    指针          定义时候不需要赋值 指针变量 4个字节
const 指针
常量指针(指向常量的指针):可理解为为指向常量发明的指针
指向可以改 但是不能通过指针修改指向的值
常量指针只能规定当前指针不能修改指向的值,不能确保别的指针不改
int t,u;
const int *pa;
pa =&t; //可行,指向变量t
pa =&u; //也可行,指向变量u
指针常量(指针是不可修改的):指向变量的不可修改的指针
         指向不能改 但是可以通过指针修改指向的值
常量指针常量:指向常量的不可修改指向的指针,不可以改指向,也不可以改指向的值
        
const 引用 const引用可以与常量绑定,也可以与变量绑定,只是不能通过这个const引用
来改变绑定对象的值。例如:
int a=10;
const int &ra=a;
a=5;//正确
ra=4;//错误,不能通过引用改变a的值
 
 
注意:
    指针 测试合法性 (指针是否为NULL 是否经过赋值 是否是野指针)
    引用 不需要检测合法性
3.函数 重载 缺省 内联
     函数 ->封装代码 ->减少重复代码
        调用函数的时候 跳转 跳转需要时间+执行也需要时间
    3.1---> 内联 关键字修饰符 inline
    适合范围:短小简单的函数 程序中多次执行 减少跳转时间浪费
使用方法:在函数前面加个inline修饰符,1.直接写在类里面 2.在其他想内联的函数前面加
inline修饰符
注意:内联只有建议权,即使添加inline也吧一定是是内联(递归,继承,循环,函数嵌套)
    内联 优点 减少代码跳转时间 提高效率 空间换时间 有类型(减少安全隐患)
         缺点 内存膨胀
                
    和define对比
                #define 不是真正的函数 只是简单的代码替换 考虑运算符优先级 没有类型 (有安全隐患)
                内联解决的问题 和函数调用方式一致 有类型
                内联函数inline(放在函数开头) 关键字
                代码比较长 代码有其他函数 循环 递归 --->不会编译成内联(只有建议权)
    3.2--->重载
            重载定义 C++允许函数同名 调用的时候需要    函数名+参数
                    重载标志:函数名相同参数不一样(不包含形参名字):
                                参数个数不一样 void fun(int x) void fun()
                                参数类型 void fun(int x) void fun(double x)
                                参数顺序 void fun(int x,double y) void fun(double x,int y)
                            函数名相同 参数也一样 返回值不一样 不构成重载 int fun();   void fun(); 重定义
            意义 方便,代码重用 作用类似的函数 可以使用同一个函数名 根据参数类型区分
                                    myadd(int +int /double+int/int+double)  
                                    
    3.3--->缺省
             缺省 给函数参数设定默认值 int fun(int x,int y,int z=0)
                        目的 设定默认值 调用函数的时候不需要每次都传递参数 缺省的参数用默认值赋值
                        注意事项 1.缺省可以缺省多个参数 缺省必须从右往左
                                2.函数定义和函数声明分开写的时候 只需要声明中写缺省 定义中不写
                                3.缺省+重载一起使用的时候 调用时候 不能确定调用哪个函数-->二义性问题 特别注意下二义性问题
4.内存申请(堆)释放 new delete
    了解格式
        new申请内存 delete 释放内存
        malloc free C语言的内存申请释放
        double *p;
        申请一个double的空间
        p=new double(3.14);
5.#include<iostream>//输入输出流 input output stream流
输入:cin>>变量
输出:cout<<变量
endl end of line 换行 相当于'\n' 和文件中用的'/r'
//C++ 兼容C语言的全部语言
//stdio.h -->cstdio 去掉,h 前面加c
//cmath cstdlib ctime
二:命名空间
1.  命名空间关键字: namespace
    出现问题 函数同名 参数一样
解决问题 函数同名
    作用 组织代码 分类 防止变量/函数同名
    namespace 定义命名空间 定义格式 namespace summer{}
    using using namespace std;//使用命名空间std 标准命名空间 std
    使用命名空间中定义的函数/变量
    1.方式1 using namespace 命名空间名字
         最简单 但是会暴露命名空间里面的全部内容(失去了命名空间的意义) 不推荐使用
    2.方式2 using summer::x; 比较安全 直接声明要使用的内容 不会暴露其他内容
         如果和已有的函数或者变量发生冲突 可以手动控制
    3.方式3 最安全也最麻烦 指明函数或者变量属于哪个命名空间
                summer::x
    关于命名空间的嵌套 summer::nine::x;
    
2.  输入输出
    cin cout
    cin.get读取一个字符 /字符串
    char ch;
    ch=cin.get();//读取一个字符
    cin.get(ch);//可以读取一个字符
    char arr[20];
    cin.get(arr,20);//第一个参数数组名 第二个最大长度 读取到\n 不会丢弃'\n'(即会换行)
    cin.get(arr,20,'1');//遇到'1'提前结束
    cin.getline(arr,20);//读取到\n 结束读取并且丢弃\n(即不会换行)
    cin.getline(arr,20,' ');//最多获取20个字符 遇到空格提前结束
    输出的格式控制:头文件 #include<iomanip>//如果要用格式控制
    cout <<std::hex<<233 << endl;// hex16进制 oct 八进制 dec 10进制
    cout << setw(5) <<233<< endl;//setw(n) 设置宽度
    cout <<left<<setw(5) <<233<< endl;//left左对齐 或者 setiosflags(ios::left) //left可以改right(默认右对齐)
    cout <<setfill('0')<<setw(5) <<233<< endl;//setfill(c) 设置填充字符 默认用空格补齐
    //设置精度
    setiosflags(ios::scientific)用科学计数法(指数形式显示)
    setiosflags(ios::fixed)固定小数方式显示
    setprecision(n)//设置小数位数
    
    cout << fixed << setprecision(10) << 3.141592654 << endl;//打印10位小数
    cout.width(5);//设置宽度
    cout << 233 << endl;
3.int _tmain(int argc, _TCHAR* argv[])//命令行参数
TCHAR在unicode下是wchar_t 多字节字符集下是char类型--->换多字节字符集
    // int agrc //是后面字符指针数组大小 传入的参数个数 第一个参数 exe的路径
    // char *argv[] 字符指针数组
三.面向对象思想
1.面向过程 函数为中心 面向过程 (只关心过程 不关心数据)
    面向对象 以数据为中心
            买东西 1.挑选商品 2.买单 3.提包走人
                        顾客-->挑选物品 -->付钱-->提高走人
                        收银员 -->结账-->收钱--->找零
                        导购员-->帮忙推荐
                        写法上的转变 //danny.eat()以人为核心 eat(danny)
            //new一个对象
2.类和对象          面向对象四大特性:抽象 封装 继承 多态
    类-->(抽象) 人类 --> 特性(属性 (数据 描述)行为(函数描述))聚集体 不存在 (概念)
    对象 类--->具像出来的一个具体的实例
    类 (图纸) 对象(造出的房子)
    语法 类 -->C++结构体 +函数
3.类和结构体
    运算符 . ->
    C语言 struct stu{}; struct stu ou;
    C++的结构体 struct stu{}; stu ou;
(1)可以省略struct
                    (2)C++的结构体中可以写函数
(3)可以初始化(新标准)
    
    C++类和C++的结构体的区别
            访问权限 --> 三种访问权限 public 公有 private私有 protected 受保护
                    public 公有 不管什么位置都可以访问 (C++结构体成员默认权限)
                    private 私有 只能在类里面访问 不能在类外访问(类成员默认私有)
                    protected 受保护 和私有差不多 (目前和私有没有区别)
            类 成员变量 一般写私有 函数写公有
                    你----> 身高 年龄 -->成员变量 -->私有
                        -->填表格 -->成员函数--->公有
        
            类可以看成私有的结构体 结构体可以看成公有的类
            结构体 纯数据
            类 数据+和数据相关的函数
C++新语法中 可以直接在类里面赋值
    
        用户不需要知道类中到底有什么成员 可以使用就OK
        数据不为用户所知可以避免用户错误修改
        私有成员(成员函数/成员变量) 在类的成员函数中进行访问 修改
        用类定义变量 --->对象
        结构体定义变量-->结构体变量
        对象
3.this 指针 ,所有成员函数都有一个this指针,指向当前操作的对象,一般缺省
this->变量
四.构造析构
1.构造函数 (构造器) 作用 给类中成员赋初值
函数名 和类名相同 没有返回值 当对象出生的时候会自动调用一次构造函数
如果调用有参构造的时候 记得加括号
    没有自己写构造 会分配一个默认构造(没有参数的构造函数 不做事情)
2.析构函数 (析构器) 作用 释放对象占据的堆区的内存(有指针的情况)
    函数名 ~加类名 没有返回值 没有参数 析构在对象死亡的时候自动调用
深拷贝必须写析构函函数
3.new delete 和 malloc free的区别
new 一个对象 本质是运算符,通过malloc继承而来 会调用构造函数 (new一个的话 可以传递参数)
    delete 会调用对象的析构
    malloc和free不会调用构造和析构 不会给成员赋初值
malloc 本质是函数
    delete 和delete[]的区别 delete只会调用一次析构
    delete[] 调用全部对象的析构
    realloc(追加内存) 原理 :
    1.在原内存后面如果有足够的内存 就直接申请后面的内存 返回首地址
    2.如果原内存后面没有足够的内容 那么另外单独申请一块内存 将原内存
            的内容拷贝到新内存之后 释放掉原内存 返回新内存的首地址
4.const成员变量 必须使用(初始化形参列表)进行初始化
    const变量 const int x; const int y;
    const成员只能通过初始化形参列表赋值
    非const成员 可以用初始化形参列表赋值 也可以直接用 =
    如果类中有const成员 所有构造函数都要给这个成员赋值
    const成员函数 在成员函数后面加上const 作用 不能在里面修改成员变量的值
                    防止修改成员的值 不能调用非const成员函数
const myfun(const int x)const
第一个const修饰返回值不可修改
第二个const修饰参数不可修改
第三个const修饰成员变量不可修改,且不能调用非const成员函数
5.类的几个默认函数 --> 构造 析构 拷贝构造 重载
附录:
    const +指针
    const int *p 常量指针 const修饰*p *p不能修改 p可以改指向 //int const *p
    int *const q 指针常量 const修饰q q不能修改 *q可以 (类似数组名)
    const 引用 引用-->对象的外号 它不能重新绑定其他对象-->常量
    const int&a=b;//--->引用不能修改绑定的a的值
    const 引用 函数传参 1.引用提高传参效率 2.const防止通过形参修改实参
五.拷贝构造
1.拷贝构造
    一种比较特殊的构造函数-->参数是这个类的对象的引用
        比如stu类 构造函数参数是stu类型的对象 拷贝同类型对象的值
    特点 构造函数 类型 同类的对象 参数必须加引用
        调用时机 :用同类型对象去拷贝的时候 函数传参的时候 形参拷贝实参的值
    
    引用传参 没有涉及形参拷贝实参 所以会提高效率
    类中有多个构造函数 但是拷贝构造只有一个
    编译器 生成四个默认函数 --->默认构造 析构 拷贝构造 重载= 如果写了 就不帮你补了
    默认构造 直接定义对象 没有参数 定义对象数组 new 没有参数的构造函数
    析构 整个类只有一个析构
    **拷贝构造 函数传参 =
1.写法 里面一定要用引用 2.注意深拷贝和浅拷贝
arr = other.arr;第一种 直接赋值 浅拷贝 编译器提供的拷贝构造是浅拷贝
    arr = new char[size];第二种 另外申请内存 深拷贝 避免使用浅拷贝
    string类 C++中用来存放字符串的一类 实现方式 动态数组
2.const和static成员    
    static 静态
        1.定义全局变量 内存静态存储区 只开辟一次内存 只在当前文件使用(不能用extern拓展)
        2.定义在函数里面 静态存储区 开辟一次内存 函数结束不释放内存
        3.类中定义static成员 static成员属于这个类 不属于某个对象 所有对象共用
            静态成员变量 必须类外赋初值
        static 成员变量 必须类外初始化 属于整个类 所有的对象都能使用
     static 成员函数 不属于对象的成员函数 不能使用非static成员
            static修饰成员函数 静态成员函数
            //没有this指针
            //不能在里面调用非static成员函数 不能使用非static成员
    const 常属性
            const+成员函数 不能调用非const成员函数的值 不能调用非const成员函数
            const+成员变量 只能用 初始化形参列表 赋值
             const属性 常量不能作为左值
六.友元和运算符重载
问题:私有成员 不能在类外访问/赋值
多次访问 使用这个成员 通过函数访问 效率不高
提高效率 -->友元 将某个函数或者某个类声明为一个类的友元friend 可以在类外访问它的私有成员
1.友元
类中的成员 建议全部私有属性 不能类外访问
友元 提供类外访问的方式 优点 提高效率 缺点 破坏了类的封装性 数据的隐藏性 代码可维护性变差
友元 它不属于成员函数 可以在类中定义 (友元 不是成员函数 没有this指针)
类外定义不需要加上类名
声明位置不限制 (私有保护公有声明都一样)
友元函数 (运算符重载)
友元类(使用不多)
类A 类B声明为类A的友元 类B的所有成员函数 都是类A的友元函数
问题1 类A是不是类B的友元 友元单向
问题2 类A是类B的友元 类C是类A的友元 类C 和类B 友元不能传递 朋友的朋友不是朋友
class B;//前向定义
class A
{
public:
    void fun(B&other);
private:
    int x;
    friend class B;//表示B是A的友元类
};
class B
{
public:
    void fun(A&other)
    {
        other.x = 3;//在B的成员函数中直接访问A类型对象的成员
    }
private:
    int x;
};
2.运算符重载
运算符重载 针对新类型变量进行运算 对原有的运算符进行改造
            改造之后的运算符功能必须和原有运算符 相似或者相仿
            不要没有目的写运算符
2.1 只能重载已有的运算符 不能创建新的运算符
2.2 运算符操作数 优先级 语法结构不能改变
    返回值为引用 意义
    返回值不为引用 多调用一个拷贝构造 (说明 新对象出生)
    返回值为引用 没有调用构造函数(说明没有对象出生)
    返回对象 --->返回的不是函数里面的对象           而是返回一个新的临时对象(立刻死亡)
     新对象 拷贝的是返回的对象
                 对临时对象++ 不等价对a++
    加引用 返回的不是临时对象 是这个对象的引用
        对引用++ 等价对a++
        返回值是临时对象 不能使用引用 *this返回值
        
        返回值加引用 连续 赋值 操作 ++++a a+=b+=c
1+1 +--->函数名 两个参数 参数类型 返回值
不能实现对象相加 --->没有对应的函数可以调用
运算符重载 目的 实现对象之间的使用运算符进行运算
算术运算符 + - * / %
关系运算符 == != > >= <= <
逻辑运算符 && || !
自增自减 ++ --
单目运算符 + - 取地址& 解引用*
位运算 & | ~ ^
必须为友元 重载了输入输出运算符 << >>
赋值运算符 += -= *=   
必须为成员 () [] -> =
       
不能重载的运算符 .点运算符 三目运算符 sizeof 域名解析符:: 成员指针运算符(.)*
单目 推荐 成员函数 双目写友元
//重载为友元
重载-
friend myInt operator-(const myInt&a, const myInt&b)
{
    myInt temp;
    temp.x = a.x - b.x;
    return temp;
}
重载+
friend myNum operator+(const myNum&a,
myNum&b)
{
    return myNum(a.x + b.x);//直接返回
 
}
前++
myInt& operator++() //返回一个引用
{
    ++this->x;
    return *this;
}
后++
const myInt operator++(int)//括号里面加上int 区分后++ 后++返回的是常量
{
    //后++ 返回加之前的 x=4 y=x++
    myInt temp;
    temp.x = this->x;
    this->x++;
    return temp;//返回加之前的值
    //返回的是临时对象
}
重载!=
bool operator!=(const myNum& a, const myNum& b)
{
    return a.x != b.x;//两个对象是否相等 比较的是成员
}
重载&&
bool operator&&(const myNum& a, const myNum& b)
{
    return a.x&&b.x;
}
myNum& myNum::operator++()
{
    ++x;
    //std::cout << "对象的值是" << x << std::endl;
    return *this;
}
std::ostream& operator<<(std::ostream&os, myNum&a)
{
    os << a.x;
    return os;
}
std::istream& operator >> (std::istream&is, myNum&a)//重载输入
{
    is >> a.x;
    return is;
}
重载& 取地址符
int *myNum::operator&()//重载& 取地址
{
    return &x;
}
重载+=
myNum&myNum::operator+=(myNum&a)//重载+=
{
    this->x += a.x;
    return*this;
}
重载new运算符
void*operator new(size_t size)
{
    return malloc(size);//返回申请的空间
}
重载delete运算符
void operator delete(void *ptr)
{
    free(ptr);//释放内存
}
重载()
void operator()(int x)//参数和返回值均
返回值参数无限制
{
    std::cout << x << std::e
}
重载[]
int &operator[](size_t index) //返回数
引用 参考 string vector
{
    return arr[index];
}
重载->
node*operator->()
{
    return &z;//返回结构体的地址
}
重载= 赋值
myNum&operator=(myNum&other)
{
    x = other.x;
    return *this;
}
七.继承一
继承:通过继承机制,可以利用已经有的数据类型来定义新的数据类型.所定义的新的数据类型,不仅拥有新定义的成员,而且还拥有所有旧的成员.我们把已经存在的数据类型叫父类(基类)新的数据类型叫子类(派生类)
格式:class 类名:public 父类名{};
注意:父类不可以访问子类的成员方法
父类的私有成员变量在子类存在,但没法使用.
父类如果有缺省构造函数,子类构造函数会自动调用父类构造
父类没有缺省构造情况下,子类必须在初始化列表中主动调用父类构造函数构造对象,因为先有父类再有子类.
隐藏:子类有父类相同函数名的函数则构成隐藏,子类有父类方法,但是默认调用子类.如果需要主动调用父类方法,则必须加上父类作用域解析限定.
例如:ch.father::Show();
构造析构调用顺序:
构造:首先构造爷爷,再构造父类,在构造子类.
析构:先析构子类,再析构父类,再析构爷爷类.
has-a:在一个类中定义了另外一个对象,另外一个对象是当前类中的组成部分.
只可以访问对象中公有成员.
总结:对于public继承,父类属性不变(public属性还是public,protected还是protected,如果是私有所有继承方式都不可以访问)
对于protected:父类所有属性变成protected(私有不访问)
对于private:父类所有属性都变成private(父类私有没法访问)
属性关系图: public属性在任何地方都可以访问
private只可以在本类中访问,其他任何地方都不可以
protected可以在当前类和子类中访问.
派生关系 基类的public 父类保护 基类的私有
public public 保护 不可访问
private private private 不可访问
protected protected protected 不可访问
 
继承二
1.多继承
    多个父类共同派生出一个子类 子类包含父类的所有成员变量和所有函数
     写法 和单继承类似 多个父类用 逗号隔开
2.多个父类中的同名函数 子类继承多个同名函数 调用的时候不知道调用哪个 (二义性) 用类名区分
     子类重写 父类函数得到隐藏
3.继承之后 构造函数的问题
    继承之后 子类会调用父类的构造函数
    多继承 子类会调用所有父类的构造函数 (在初始化形参列表中调用)
                调用父类构造的顺序和继承顺序有关
            析构 函数调用的顺序和构造顺序刚好相反
C++支持多继承 --->尽量避免多继承
4.菱形继承 虚继承
    A-->B C ---共同派生出一个新的类D 导致 祖父类的成员变量 在孙子类中有两份拷贝
    virtual 虚继承 (唯一目的 解决菱形继承的问题)
    B C虚继承A
    两个父类写虚继承就可以了
5.虚继承的目的防止菱形继承 大致的原理(偏移量)
6.子类指针 不能指向父类(父类的成员 父类的函数) 访问容易越界
八.i/o流
i/o 输入输出流 cin cout
            文件io流
            C语言学过 FILE* 文件指针 +文件操作的函数 fopen fclose fprintf
                        rt rb
                    文本文件(txt) 字符流 123 -->存3个字符 不会乱码
                    二进制文件(其他文件) 字节流 123 这个是int-->4个字节 打开文件看可能会乱码
            C++ 文件对象 fstream
            int x=0x334455; 4个字节 写入内容 0x334455
                字符流-->"3359829" 7个字节
                fprintf fscanf fgetc
                fread fwrite
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
    fstream file;//文件对象 (通过文件对象操作文件)
    file.open("./文件/1.seven",ios::in|ios::out);//打开文件 第一个参数 文件路径 +打开方式 //ios::out 文件不存在就创建文件
    //ios::in 读取 ios::out 写入 ios::app 追加 ios::binary 二进制文件 用|连接
    //"D:\Documents\Visual Studio 2013\Projects\20180413_21期C++11_io流\io流\文件\1.txt" 绝对路径 ---> 其中\换成\\ 或者/
    //当前路径 ./ 当前文件夹的上级文件夹 ../
    //C语言判断文件指针是否为NULL
    //判断文件是否打开成功
    if (file.is_open())//返回值为true 打开成功 不然打开失败
    {
        cout << "打开成功" << endl;
    }
    
    char ch, arr[10];
    //文件操作的函数
1.get put 读取字符
    file.get//读取文件中的一个字符/字符串
    ch = file.get();//读取一个字符 通过返回值得到读取的内容 没有参数
    file.get(ch);//通过参数获取得到的内容
    file.get(arr, 10);//数组名+数组大小
    file.get(arr, 10, ' ');//最后一个参数的意思是 读到这个字符的时候提前结束读取
    for (int i = 0; i < 26;++i)
        file.put(i+'A');//写入字符
2.getline 读取字符串
    file.getline(arr, 10);
    file.getline(arr, 10, ' ');
3.运算符重载 << >> 字符流
    file << "hello world"; //file<<写入文件 file>>读取文件内容
    file << 33;
    file >> arr;
    cout << "读取的数组是"<<arr << endl;//注意下数组越界问题
    cin.get();
    file.close();
    file.open("文件/2.summer", ios::binary | ios::out|ios::in);//创建二进制文件
    | 二进制或的意思 顺序没有限制
4.read write 二进制文件
    strcpy(arr, "hello");
    file.write(arr, 10);//第一个参数 指针(必须是char*类型) 第二个参数 大小(单位是字节) 写入
    int x = 3;
    file.write((char*)&x, sizeof(int));//其他类型的指针 必须进行强转
    file.read(arr, 10);//参数和write一样 用字节做单位 读取内容
5.文件指针偏移
    //fseek ftell
    std::streamoff off=file.tellp();//文件内部指针偏移量 返回值
    file.seekp(0,ios::cur);//根据偏移量移动指针
    //ios::beg 文件开头 ios::end 文件末尾 ios::cur
    file.close();//关闭文件(保存)
    return 0;
6.remove 删除文件 remove(文件路径)
}
九.异常处理
三个关键字 :
try 尝试
catch 捕获异常
throw 抛出异常
异常处理的机制 :内存申请失败 / 文件不存在 --->异常(代码没问题 外部问题导致的问题)
try
{
    //异常代码块
    throw 异常;
}
catch(异常)
{
    //处理
}
异常处理的多层机制
异常如果没有捕获到 捕获到没有处理 --->往上级丢包袱
村长-->县长--->省长---> (最终没有处理就 abort函数 中止程序 )系统调用 中止程序
多层机制--->嵌套
terminate
处理了继续往下执行
示例代码:
try//一个try可以用多个catch来进行处理
{ //try中throw只会执行一个
    fp= fopen("1.txt", "r");//错误原因 没有文件 代码是没有问题
    if (fp == NULL)
    {
        throw "文件打开失败";//后面丢出异常 异常可以是任意类型 (类似return)
    }
        //throw std::string("hello world"); //示例代码 返回一个string类型的临时对象
}
catch (int x)//捕获某种类型
{
    //如果说丢出int类型异常 被这个catch捕获并且处理
    std::cout << "捕获的int类型的异常" << std::endl;
}
catch (std::string st)//string类型的异常
{
    std::cout << "捕获的string类型的异常" << std::endl;
}
catch (char array[])//字符串类型
{
    std::cout << "捕获的字符串类型的异常" << array << std::endl;
    //处理异常的代码 如果说没有没有处理 -->异常仍然会在
    fp = fopen("1.txt", "w+");//创建文件
}
char arr[10];
fread(arr, sizeof(int), 10, fp);
fclose(fp);
十.模板
模板(类型参数化) 写和类型无关的代码
函数模板 针对参数类型不一样的函数
类模板     针对于成员类型不一样的类(链表 数组)
关键字 template typename(表明类型的名字)
1.函数模板
template<class T>//模板头 class 可以换成typename 表示一种类型
T fun(T x)
{
return x;
}
fun<int>(3,4)//显示传入类型
//可以通过参数推导出T的类型 类型 可以省略 fun(3,4)--->隐性调用
//函数模板--->传入参数的类型----->生成具体的模板函数 ----->调用,模板函数
//关于重载部分 可以重载
函数模板 调用时候 通过参数推导类型 所以可以不写类型
如果有同名函数 调用顺序
函数参数匹配 先调用现有的函数--->对应的模板函数--->(类型转换匹配)现有函数
重点 1.定义模板和调用 2.调用顺序 3.概念(模板函数 函数模板)
类模板 --->stl 标准模板库 vector list map
template <class T>
class myvector
{
T data;
}
//通过类模板生成,模板类 定义模板类的对象
1.模板类的成员函数 类外定义的话 需要加类名 <T>
2.定义模板类的对象的时候 必须显示指明类型
3.类模板的声明和定义 不要分到多个文件 直接全部写.h
代码 ----->类型
链表 数组
结构体
struct node
{
    int data;//数据域
    struct node*next;
};
vector示例代码:
template < class T>
class myVector//动态数组 指针 指向堆内存
{
private:
    T* data;//数组
    int size;//数组大小
    int len;//数组中有多少个数据
public:
    myVector(){ data = new T[10], size = 0, len = 0; }
    myVector(const myVector&other)
    {
        size = other.size;
        len = other.len;
        data = new T[size];
        memcpy(data, other.data, sizeof(T)*len);//内存拷贝
        cout << "调用拷贝构造" << endl;
    }
    ~myVector()
    {
        if (data != NULL)
        {
            delete[]data;
            data = NULL;
        }
    }
    void insert(T data);//插入数据
    myVector operator+(const myVector&other);
};
template<class T>
void myVector<T>::insert(T data)
{
}
template<class T>
//myVector<T> myVector<T>::operator+(const myVector<T>&other)
myVector<T> myVector<T>::operator+(const myVector<T>&other)
{
    //具体代码先不写
    return *this;
}//类外定义 ---><T> 模板类
十一:C11的新标准(10条)和类的常量成员
C11的新标准:
1.初始化变量方式
    int a=10;//C的方式
    int a(10);//C++的方式
    int a{10};//C11的方式
2.空指针 NULL #define NULL 0 int类型的常量
    C++ nullptr (void*)0
    用nullptr替代 NULL
3. 自适应类型 auto 根据初始化赋的值 确定变量类型(必须初始化 同时定义多个变量 类型保持一致)
     fun
     auto x=fun();//
4.decltype 类型声明
    有一个变量 用这个变量的类型定义另外一个变量
    //declare
    decltype(arr) brr;//一个()定义同类型的对象/变量
    decltype((arr)) crr=arr;//两个() 定义的是引用类型
5.for的新用法 一般和auto搭配
    遍历 容器/...
    vector string
    string st = "hello world";
    for (auto s : st)//只适用于有迭代器的类 (迭代器(数据结构讲))
    {
        cout << s;// << '\t';//打印所有的元素
    }
6.类型取别名
    C语言 typedef
    C++ using
    给int取别名INT
    typedef int INT;//C语言的方式
    using INT=int;//C++取别名方式
7.类中直接给成员赋值
    //用构造函数赋值 一般不在类中
8.类的默认构造
    A()=default;//不写函数体 保留默认构造
9.委托
    在自己的构造函数中调用其他构造函数帮忙做事情
    委托自己的其他构造函数来给成员赋值
10.final 最终的意思 防止多态的时候重写(虚函数重写) 虚函数重写
修饰类 类无法被继承
    修饰父类虚函数 虚函数子类不能重写
强转:
int x = (int)3.14;//C语言的写法
int y = int(3.14);//C++里面的强转
四个C++的强转方式
格式 static_cast<double>(3)
static_cast 不检查类型 直接强转 优点 明显
const_cast 把const指针 /引用 转换非const指针 /引用
reinterpret_cast 地址转int int转地址
dynamic_cast 多态的时候检查安全性 (子类指针 指向父类 检查是否安全 )
智能指针: auto_ptr 头文件:<memory>
auto_ptr<B> ptr(new B);//给智能指针赋值
    ptr生命周期结束之后 自动释放堆区内存
    ptr 中有一个成员指针 指针指向这
    ptr生命周期结束的时候调用析构 析构中delete这个指针
    用的是delete 没用delete[] 所以不能管理数组 堆区对象
联翩:
静态联编    一般函数 编译方式 编译阶段确定 调用效率高 灵活性差
动态联编 多态中的虚函数 程序运行的时候动态调用 调用效率低 但是灵活
示例代码:
template<class T>
bool max(T a, T b)
{
    return a > b;
}
template<class T>
bool min(T a, T b)
{
    return a < b;
}
//冒泡排序 数组 +数组大小 +从大到小
template<class T>
void sort(T arr[], size_t size, bool(*p)(T, T))
{
    T temp;
    for (size_t i = 0; i < size - 1; ++i)
    {
        for (size_t j = 0; j < size - 1 - i; ++j)
        {
            if (p(arr[j], arr[j + 1]))
            {//交换
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
class A
{
public:
    A() = default;//不想写函数实现 但是希望保留默认构造
    A(int x){ cout << "hell:"; }
};
class B
{
    int x, y;
public:
    B(){ x = 0, y = 0; cout << "调用了无参构造"; };
    B(int x) :B(){ cout << "调用了有参构造"; }//先初始化形参列表 然后函数体
    ~B(){ cout << "析构函数" << endl; }
    void put()
    {
        cout << "[" << x << "," << y << "]" << endl;
    }
};
class C //final
{
public:
    virtual void fun()final
    {
        cout << "fun" << endl;
    }
};
class D :public C
{
public:
    //void fun()//不能重写 final修饰的函数
    //{
    //  cout << "子类" << endl;
    //}
};