C++学习笔记

一、从C到C++
1、C++的介绍
创造者:
    丹麦   科学家    bjarne stroutrup
    sumla语言:第一个面向对象的语言,引入了类和对象机制    
    algol语言:是一门关于算法的语言,结构体系非常优美
    在1973年,被美国的贝尔实验发现,开进C语言
    在1983年,C++诞生了,C with  Class,在C的基础之上加了面向对象的机制

1983年,贝尔实验室(Bell Labs)的Bjarne Stroustrup发明了C++。 C++在C语言的基础上进行了扩充和完善,
是一种面向对象程序设计(OOP)语言。
Stroustrup说:“这个名字象征着源自于C语言变化的自然演进”。还处于发展完善阶段时被称为“new C”,之后被称为“C with Class”。C++被视为C语言的上层结构,1983年Rick Mascitti建议使用C++这个名字,就是源于C语言中的“++”操作符(变量自增)。而且在共同的命名约定中,使用“++”以表示增强的程序。

支持面向对象编程、泛型编程和过程化编程、函数式编程(C++的新特性:Lambda表达式)。

编程领域广泛:常用于系统开发,引擎开发等应用领域,是最受广大程序员喜爱的编程语言之一。
        流星蝴蝶剑(修仙类)
        VR虚拟现实(图形库)
        google的地图底层开发语言
        极品飞车
        WPS底层开发
        服务器端的开发
        .......    
历史:
“C with Class”阶段,C语言基础上的特征主要有:类及派生类、共有和私有成员、构造函数和析构函数、友元、内联函数、赋值运算符的重载,等等。
1985年1.0版新增加:虚函数的概念、函数和运算符的重载、引用、常量,等等。
1989年2.0版新增加:类的保护成员、多重继承、对象的初始化与赋值的递归机制、抽象类、静态成员函数、const成员函数,等等。
1993年3.0版本新增加:模板(template),解决了多重继承产生的二义性及其构造/析构函数的处理问题,等等。
1998年C++语言及库标准化:名字空间、标准模板库(STL)、通用算法类和字符串类型,等等。该标准通常简称ANSI C++或ISO C++ 98标准,此后每5年更新一次标准。
2003年通过了C++标准第二版(ISO/IEC 14882:2003)C++03:这个新版本是一次技术性修订,对第一版进行了整理—修订错误、减少多义性等,但没有改变语言特性。
国际标准化组织于2011年9月1日出版发布《ISO/IEC 14882:2011》简称ISO C++ 11标准,取代现行的C++标准、C++98和C++03。
2、C++是C的增强
(1)C++是静态类型的语言,具有严格的数据类型检查
例如:
C:
    const int a=10;
    a=20;  //报错
    int *p=&a;
    *p=20;
    //a的值?
test1.c:6:9: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
    6 |  int *p=&a;
      |         ^
ubuntu@l

C++:
    const int a=10;
    a=20;  //报错
    int *p=&a;
    *p=20;
est2.cpp: In function ‘int main()’:
test2.cpp:6:9: error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]
    6 |  int *p=&a;
      |         ^~
      |         |
      |         const int*
(2)新增了变量引用
引用符号:&(在C语言表示取地址,在C++里另外一层表示引用)
    引用:是给已经存在的变量取一个别名,称为“引用”,别名和原来的变量名是同一个
引用的声明:
    数据类型(内置的数据类型或自定义的类类型)  &    别名  =  已经存在的变量名 ;
例如:
    int  zhang_Three=10;
    int   & small_Three =  zhang_Three;


    例如:
        int  a=10;
        int &b;
        b=a;  
        报错:
            test2.cpp:10:7: error: ‘b’ declared as reference but not initialized
               10 |  int &b;
                  |       ^
常见的面试题:
    引用和指针的区别?
    (1)编译器会为指针变量申请另外的空间,但是编译器不会为引用类型的变量额外开辟空间
    (2)指针变量存在时可以不用进行初始化,但引用变量一旦存在必须进行初始化工作
    (3)指针变量可以指向多个已经存在的变量,引用变量是对应一个已经存在的变量(一一对应)
    (4)指针可以有多级,而引用只有一级
练习:
    通过函数实现两个数的交换
    
(3)新增了函数重载以及运算符重载
1)函数重载
    概念:函数名相同,函数的参数个数、顺序、类型不同,就称为“函数重载”
例如:
C语言:
    void  function(int a   ,  char  b)
    {

    }
    void  function(int a)
    {

    }  //报错:标识符重名的错误
C++:
    void  function(int a   ,  char  b)
    {

    }
    void  function(int a)
    {

    }  //正确    
    
    注意点:
        函数重载是与函数的返回值无关
2)运算符重载(放在后面讲)

(4)C++新增了带默认值参数的函数
格式:
    返回值   函数名(参数1=初始值1,..........)
    {

    } 
例如:
    void  function(int  a=10)
    {
        
    }
调用:
    不需要更改参数的值:
        function();
    更改参数的值:
        function(20);
注意:
    void  function(int a=10,  int  c)
    {

    }
    调用:
        function(20);//报错
        test2.cpp:25:28: error: default argument missing for parameter 2 of ‘void function(int, int)’
       25 | void function(int a=10,int c)
          |                        ~~~~^
        test2.cpp:25:19: note: ...following parameter 1 which has a default argument
           25 | void function(int a=10,int c)

    void function(int  a ,  int  c=10)
    {

    }
    调用:
        function(20);
        规定:
            函数中携带默认值的参数需要放在不携带默认值的参数后(针对于多个参数讲)

概念:
    内联函数
    是指:程序在编译过程中直接进行展开,就不需要在执行时对于函数的参数、局部变量、函数地址等入栈/出栈操作
    内联函数的声明:
        关键字:inline
        格式:
            inline   返回值    函数名  ([参数1,..........])
            {
                
            }
        调用:
            函数名([实参1,....])
        例如:
            inline  void function()
            {

            }
            调用:function()
    用途:
        适用于短小且使用率非常高的代码,内联函数中一般不会放置循环结构
        例如:
            inline  int get_Max(int a, int b)
            {
                return  a>b?a:b;
            }
    面试题:
        对于一段精简、使用频度高的代码,C语言如何实现才能提高效率,C++如何实现才能提高效率?
                C++中将这段代码声明为内联函数
                C语言使用宏来实现
                    #define  get_Max(a,b)  a>b?a:b
                    #define   sum(a,b)       (a)*b
                        int  sum_result=sum(10+20 , 30) ;
        
(5)新增异常处理
    C++可以主动产生异常,并捕获异常进行处理

(6)新增面向对象机制
    封装、继承、多态等等
(7)智能指针
    用于帮助用户管理堆内存空间
...

3、C++的编译流程
    与C一样,在Linux中编译C++代码,一般采用g++
    ###################请你阐述C/C++的编译流程,以及每个流程中执行的工作任务################
(1)预处理
a、将除源文件以外的内容全部加入到源文件中
b、进行宏替换工作
c、删除掉注释
(2)编译
a、检查用户编写的代码是否符合C++语法规范
b、将用户编写的代码翻译成汇编语言
(3)汇编
a、将汇编语言翻译成机器语言
(4)链接
a、生成可执行文件

4、C++的文件架构以及扩展名
(1)主程序文件
    该文件中包含main函数,一般放置类的声明与实例化,函数的声明与定义等等
(2)源文件(一般是以.cpp为主)
    源文件的后缀名一般是.cpp、.cxx、.cc等等,一般放置类的成员函数实例化、函数的定义等等
(3)头文件(一般是以.h为主)
    头文件的后缀名一般是.h、.hpp、.hxx等等,一般放置类的声明、变量的声明、函数的声明等等


二、命名空间与内存分配
1、命名空间
    又称为“名字空间”,在内存(全局)中取一块区域并对其进行命名
实际例子:
    同一个班级,两个同姓的人,例如:张三和张三,其中一个张三座位是在讲台右边,另外一个张三座位是在讲台左边(将两个张三,放置在不同的区域里)
    程序中,有两个一样的标识符(两个变量),编译器会提示标识符重名的问题,如何解决:将两个标识符放在不同的区域中
    C++中的解决:
        使用命名空间解决标识符重名的问题

有名的名字空间:
关键字:namespace
声明格式:    
    namespace   命名空间的名称    //名称符合C/C++语法规范即可
    {
        //代码
    }
    
无名的名字空间
关键字:namespace
声明格式:    
    namespace     
    {
        //代码
    }
    #########注:全局作用域其实质就是一个无名的名字空间    

如何访问名字空间里的内容:
1)直接访问:访问命名空间中指定的内容
符号:“::”,域作用符号
格式:
    命名空间名称   ::命名空间里的内容;
例如:
    namesapce  zhangsan
    {
        int  a=10;
    }
    zhangsan::a   //访问名字空间中的变量a

2)通过using关键字访问命名空间中指定的内容
关键字:using
格式:
    using  命名空间名称  :: 命名空间中的内容;//将命名空间中的内容导入到using所在的空间中
例如:
    using  zhangsan ::a;

3)通过using和namespace关键字访问命名空间中所有的内容
关键字:using、namespace
格式:
    using namespace 命名空间的名称  ;   //将命名空间里的所有内容导入到using\namespace所在的作用域(空间)中
例如:
    using namespace zhangsan;

4)命名空间也支持嵌套
格式:
    namespace      名称1
    {
        namespace  名称2
        {
            namespace 名称3
            {
                ............
            }
        }
    }

例如:
namespace name1
{
    int  a = 30;
    namespace name2
    {
        int a = 40;
        namespace name3
        {
            int a = 50;
        }
    }
}
如何访问:
    name1::name2::name3::a  ;//访问name3中的a

2、内存分配
    面试题:
        C语言里的malloc和free与C++里的new和delete有什么区别?

    C语言:
        malloc:用于动态内存分配
        free:释放动态内存
    C++:
        new:用于动态内存的申请
        delete:用于释放申请的动态内存
    1)C语言中malloc和free适用于内置的数据类型,C++中的new和delete不仅适用于内置的数据类型,还适用于自定义的类型(类类型)
    2)C语言中使用malloc时,需要进行强转,但C++使用new不需要强转
    3)C语言中使用malloc申请空间时需要指定空间大小,但new不需要指定大小
    4)C语言中的malloc是函数,而new不是函数,其实质就是一个操作符
    5)C语言中的malloc申请空间时没有向空间中存放初始值,但new申请空间时可以存放初始化值
new和delete的使用:
(1)new申请变量地址空间
格式:
    数据类型(内置的数据类型和自定义的类型)   *   标识符  =   new   数据类型;
    或
    数据类型(内置的数据类型和自定义的类型)   *   标识符;
    标识符  =   new   数据类型;
例如:
    int   *  p  =  new   int  ;   //在堆区new了int大小的空间,并用指针变量p指向该空间
    或
    int    * p ;
    p= new int; 


    People类型
    People   * people = new People ;  //申请People大小的空间,并用people指向该空间
释放申请的空间:
格式:
    delete  标识符
例如:
    delete  p;


1)new申请空间时向空间存放初始值
格式:
    数据类型(内置的数据类型和自定义的类型)   *   标识符  =   new   数据类型(初始值);
    或
    数据类型(内置的数据类型和自定义的类型)   *   标识符;
    标识符  =   new   数据类型(初始值);
例如:
    int   *  p  =  new   int(50)  ;   //在堆区new了int大小的空间,并用指针变量p指向该空间,并且向空间中存放初始值50
    或
    int    * p ;
    p= new int(50); 

(2)使用new开辟数组空间
格式:
    数据类型(内置的数据类型和自定义的类型)   *   标识符  =   new   数据类型 [ 数组的大小];
    或
    数据类型(内置的数据类型和自定义的类型)   *   标识符;
    标识符  =   new   数据类型[ 数组的大小];
例如:
    int   *  p  =  new   int[5]  ;   //在堆区new了5个int大小的空间,并用指针变量p指向该空间
    或
    int    * p ;
    p= new int[50]; 

1)new申请空间时向空间存放初始值
格式:
    数据类型(内置的数据类型和自定义的类型)   *   标识符  =   new   数据类型 [ 数组的大小]{初始值1,初始值2,........};
    或
    数据类型(内置的数据类型和自定义的类型)   *   标识符;
    标识符  =   new   数据类型[ 数组的大小]{初始值1,初始值2,........};
例如:
    int   *  p  =  new   int[5]{1,2,3,4,5}  ;   //在堆区new了5个int大小的空间,并用指针变量p指向该空间
    或
    int    * p ;
    p= new int[5]{1,2,3,4,5}; 

释放空间:
格式:
    delete  [] 标识符;

例如:
    delete  [] p;


C++里的作用域:
(1)局部作用域
    数据存在于代码块内部的区域,称之为“局部作用域”,数据在当前代码块中有效,超出代码块的区域就失效
(2)全局作用域
    数据存在于文件中即代码块的外部,称之为“全局作用域”,数据对于整个文件都是有效的
(3)命名空间作用域
    是全局作用域的一部分,数据存在于命名空间中只对该空间有效,超出则无效
(4)类作用域
    是全局作用域的一部分,数据存在于类中,只读该类是有效,超出则失效


三、类和对象(重点)
1、类
    类是描述一类事物的特征和行为的统称,抽象的不存在的,泛指的概念,例如:描述一个人,从外观上(特征)和言行举止(行为)上进行描述
    外观上(特征):
        长头发
        蓝牙眼睛
        白皮肤
        带了美瞳
        年龄多大
        身高
        体重
        .....
    言行举止(行为):
        走路
        跑步
        说话
        学习
        打游戏
        .......

程序来描述:
关键字:class   -------描述一个类
格式:
    class    类名
    {
        //外观---特征
        长头发
        蓝牙眼睛
        白皮肤
        带了美瞳
        年龄多大
        身高
        体重
        .....
        //言行举止----行为
        走路
        跑步
        说话
        学习
        打游戏
        .......
    };

例如:
    class   People
    {
        //特征
        int  eyes;
        int age;
        int height;
        int weight;
        char name[20];
        .....
        //行为
        void walk()
        {}
        void run()
        {}
        void play()
        {}
        void study()
        {}
        ..........
    };
特征(属性):
    指的是变量,称为类的成员变量
行为(方法):
    指的是函数,称为类的成员函数
类的成员:
    包含了成员变量和成员函数

2、对象
    是指类的实例化(实实在在存在的),是特指的概念,例如:人类实例化对象张三、李四、王二等等
实例化的两种方式:
(1)在栈区进行实例化
格式:
    类名   对象名  ;  //类名和对象名就是标识符,满足语法规范
例如:
    People  zhangsan ; //实例化zhangsan对象
    People  lisi;
    ......
(2)在堆区进行实例化
格式:
    类名   *   对象名  =  new  类名;//在堆区开辟类大小的空间,并用对象指向该空间
例如:
    People  * zhangsan = new People ;
    People  * lisi = new People ;  //注意释放空间:delete zhangsan

3、如何访问类的成员
    通过类的对象去进行访问
(1)对象是在栈区实例化
符号:“.”
格式:
    对象名  .    成员 ;  //访问类的成员
例如:
    zhangsan.height=180;
    zhangsan.walk();

(2)对象是在堆区实例化
符号:“->”
格式:
    对象名 ->  成员 ;//访问类的成员
例如:
    zhangsan->height=180;
    zhangsan->walk();


    ############################面试题:结构体和类的区别是什么?#######################

4、类的成员访问修饰符
    C++提供了三个类的成员修饰符,public(共有)、private(私有)、protected(受保护的),作用是保护类的成员
(1)public修饰符
    一定要存在于类中
格式:
    public:
        类的成员
注:
    如果类中有其它类的成员修饰符,直到遇到下一个修饰符之前(类的后括号之前)的成员,都是用public修饰
    对于public修饰的成员:
        在类的外部可以访问
        在类的内部可以访问
        对于派生类可以访问(后讲)
        对于友元可以访问(后讲)
(2)private修饰符
格式:
    private:
        类的成员
注:
    如果类中有其它类的成员修饰符,直到遇到下一个修饰符之前(类的后括号之前)的成员,都是用private修饰
    对于private修饰的成员:
        在类的外部不可以访问
        在类的内部是可以访问
        对于派生类不可以访问
        对于友元可以访问

(3)protected修饰符
格式:
    protected:
        类的成员
注:
    如果类中有其它类的成员修饰符,直到遇到下一个修饰符之前(类的后括号之前)的成员,都是用private修饰
    对于protected修饰的成员:
        在类的外部不可以访问
        在类的内部是可以访问
        对于派生类可以访问
        对于友元可以访问
注:
    如果类中的成员没有加任何的修饰符,那么该成员默认是类的私有成员
    一般是将类的成员变量放置在private修饰符下(具体情况具体分析)
5、类的构造函数
    构造函数的作用是用于构造(创建)对象,是一种特殊的函数,如果用户没有显示的写出构造函数,那么编译器会自动生成一个隐式的不带参的构造函数;如果用户显示的写出构造函数,那么编译器不会自动生成隐式的构造函数。创建对象时会自动调用构造函数(才表示对象创建成功)
构造函数的格式:
    类名 (参数列表)
    {
        //代码
    }
例如:
    People()
    {
        //代码
    }

注:
    创建对象时,要参考构造函数是否带参,如果带参那么创建对象时就需要传递实参
    格式:
        类名  对象名(实参列表);
    例如:
        People  people(10);

    总结:
        (1)构造函数可以发生重载
        (2)构造函数没有返回值
        (3)构造函数的作用是用于构造对象,还可以初始化类的成员变量

类的成员变量的初始化方式:
(1)类的对象进行初始化
例如:
    People people;
    people.num=10;  
(2)类的构造函数中初始化
例如:
    People(int  a)
    {
        num=a;   //用a来初始化类的成员num
    }
(3)通过类的构造函数的初始化列表的形式
格式:
    类名 ([参数列表]):成员变量1(初始值),成员变量2(初始值),.......
    {
        //代码
    }
例如:
    People():num(10)  //创建对象时,对类的成员变量num进行初始化为10
    {

    }

注:
    构造函数的调用方式:
        (1)实例化对象的方式调用----构造函数的隐式调用
        (2)直接通过类方式调用-----构造函数的显示调用
            格式:
                类名([实参列表]);
            例如:
                People(10);//构造函数的显示调用

练习:
    设计一个游戏,游戏可以设置一个角色或者多个角色,创建武器类、药瓶类供游戏角色选择性的装备
    角色:
        满血量100
        使用武器进行攻击,可以选择使用什么样武器进行攻击,可以选择攻击某个游戏角色(可以装备武器)
        使用药品进行回血,可以选择使用什么药品进行回血(可以装备药品)
    武器:
        刀    ---  伤害-5
        剑    ---  伤害-10
        弓弩 ---  伤害-10
        手枪 ---  伤害-80
        大炮 ---  伤害-100
        ....
    药品:
        绷带  --- 回血+5
        饮料  --- 回血+10
        止痛药 ---回血+15
        急救包 ---回血+50
        医疗箱 ---回血+100
        .....

6、类的拷贝构造函数
    拷贝:将原来的对象里的内容重新复制一份,用原来的对象来初始化新的对象
    如果用户没有显示的写出拷贝构造函数,那么编译器也会自动生成一个拷贝构造函数,如果用户显示的写出,那么编译器不会自动生成
C语言:
    int  a=10;
    int  b=a;
C++:
    People  people1;
    People people2=people1;  //运算符重载,直接赋值拷贝,类似于C语言的形式

    拷贝构造:
    People  people1;
    People people2(people1);     

拷贝构造函数的原型:
    类名  (const  类名  &  obj) //拷贝构造函数
    {

    }
例如:
    People(const People &obj)
    {

    }


拷贝构造函数又分为:深拷贝和浅拷贝
    区分的前提:类中有指针变量需要去申请空间时,使用以后进行释放的操作
    浅拷贝:
        拷贝时将原理对象中的成员变量的值拷贝一份到新的对象中
        如果类中含有指针变量,并向堆区申请空间,那么使用浅拷贝会出现空间被重复释放造成程序崩溃的现象
    深拷贝:
        拷贝构造函数中,为指针重新开辟一块空间来存放值
注:
    如果类中不含有指针去申请堆空间,那么深拷贝和浅拷贝没有区别
面试题:
    什么是浅拷贝?什么是深拷贝?


7、类的析构函数
    析构函数的作用是用于释放该类所占用的资源(释放对象),在类的对象使用完时(当类的对象超出了作用域),会自动调用析构函数;如果是在堆区实例化的对象,那么当手动释放对象时,会自动调用析构函数
析构函数的原型:
    ~类名()  //析构函数
    {

    }
例如:
    ~People()
    {
        //释放资源
    }
8、友元
    C++提供友元目的是给类的外部提供一个访问类的私有成员的接口,即可以通过友元访问类的私有成员
    友:friend
友元分为友元函数和友元类
(1)友元函数
关键字:friend
格式:
    friend  函数返回值   函数名(参数列表); //声明一个友元函数
例如:
    friend  void  function();//function函数是一个友元函数

注意:
    友元函数属不属于类的成员?友元函数不是类的成员函数

将一个类的成员函数可不可以声明为另外一个类的友元?一个类的成员函数声明为另外一个类的友元,可不可以访问另外一个类的私有成员?
编译器提示错误:不可访问(提前声明类)
格式:
    friend   返回值类型  类名  ::函数名   (参数列表);

(2)友元类
关键字:friend
格式:
    friend  class   类名;   //将类声明为友元
例如:
    friend class People; 


C++第二天作业:
    (1)请阐述构造函数和普通函数的区别?析构函数和普通函数的区别?
                    析构函数:
                        1)没有返回值
                        2)不带参数
                        3)析构函数是不能发生重载
                        4)析构函数的作用是用于释放资源
    (2)请阐述什么是浅拷贝什么是深拷贝以及他们的区别?
    (3)请阐述malloc/free和new/delete的区别?
    (4) 编程实现:  
编写一个Person类,包括:
1、普通数据成员:姓名,性别,年龄。
2、三个构造函数:无参数构造函数,有参数构造函数(参数:姓名的指针,年龄,性别),拷贝构造函数。
3、析构函数。
4、输出人员信息函数print()。
编写main()函数,分别调用三种构造函数,创建三个对象P1、P2、P3,其中P3的创建是用P2通过深拷贝复制得到的。


9、this指针
    C++中成员函数的特性,在类的非静态成员函数中都会存在一个this指针,来指向当前类,它是隐式的不可见的,是作为函数的第一个参数
    可以通过this指针来解决二义性的问题
this指针原型:
    类名    *   const   this ; //this指针的原型
例如:
    People  *  const  this;

将this指针作为函数返回值使用:
    格式:
        类名     &  函数名 ([参数列表])
        {
            //函数具体实现
            
            return   *this;   //通过该函数将当前对象进行返回
        }
10、static关键字
    C++提供的static关键字主要应用于类的成员,对于不是类的成员与C语言的作用是类似
    对于类的静态成员讲,它是类的所有对象共享一份,它不是某个对象所特有的
(1)static声明成员变量
    用static声明的成员变量是存储在静态全局区,即全局变量
    在C++中不能直接对静态成员变量进行初始化,在类外对它进行初始化
类外初始化格式:
    类型   类名  ::  变量名  =  初始值; //在类外初始化
例如:
    int   People ::  number = 10;   //在类外初始化
(2)static声明静态成员函数
格式:
    static   返回值类型   函数名 (参数列表)
    {
        
    }
例如:
    static  int  get_value()
    {

    }
静态函数的注意事项:
    1)静态成员函数中是否有this指针?答案:没有,为什么?因为存储在静态全局区
    2)静态成员函数调用非静态成员?静态成员?答案:不能调用非静态成员,可以调用静态成员
    3)非静态成员函数调用非静态成员?静态成员?

(3)类的静态成员的访问方式
1)可以通过类的对象进行访问
例如:
    People people;
    people.function();//这种方式访问
2)可以通过类进行访问
符号:“::”
格式:
    类名  :: 静态成员名 ;//能不能通过这种方式访问类的非静态成员?
例如:
    People  ::   function();

11、const关键字
    用const修饰类的成员,就表示成员是不可变,例如:修饰成员变量变量是常量属性
    C++中用const修饰类的成员函数,表示成员函数是对类的成员以只读的性质(保护数据成员)
格式:
    函数返回值类型     函数名  ([参数列表]) const
    {

    }
例如:
    void   function() const
    {

    }

四、类的继承与多态
1、类的继承
    一个新的类拥有(共享)其它一个或多个已经存在的类的属性和方法,称为“类的继承”,例如:父亲和母亲是儿子的父类
    新的类,称为“子类”或“派生类”
    一个或多个已经存在的类,称为“父类”或“基类”
    如果是拥有一个类的属性和方法,称为“单继承”
    如果拥有多个类的属性和方法,称为“多继承”
###############单继承#################
格式:
    class  新的类(子类或派生类)  :  继承权限    已经存在的类(父类或基类)
    {

    };
例如:
    class  Son  :    public   Father   //Son类继承自Father类,Son就拥有Father的属性和方法
    {
        //拥有自己特有的属性和方法
    };

2、多继承
格式:
    class   新的类(子类或派生类) :继承权限1  已经存在的类1(父类1或基类1),继承权限2  已经存在的类2(父类2或基类2),.........
    {

    };
例如:
    class  Son :  public   Father1,protected  Father2
    {

    }
注意:
    多继承(菱形继承)会出现二义性问题?解决:虚继承

3、继承权限
    C++提供了三种继承权限,分别是:public(共有)、protected(受保护)、private(私有)三种
(1)public继承
    1)父类的public下的成员是被继承到子类的public修饰符下
    2)父类的protected下的成员是被继承到子类的protected修饰符下
    3)父类的private下的成员是没有被继承到子类中    
(2)protected继承
    1)父类的public下的成员是被继承到子类的protected修饰符下
    2)父类的protected下的成员是被继承到子类的protected修饰符下
    3)父类的private下的成员是没有被继承到子类中    
(3)private继承
    1)父类的public下的成员是被继承到子类的private修饰符下
    2)父类的protected下的成员是被继承到子类的private修饰符下
    3)父类的private下的成员是没有被继承到子类中

问题:
    1)子类与父类有相同的属性或方法,那么继承之后?
        如果子类与父类有相同的属性和方法,继承之后,子类会自当屏蔽父类与子类相同的属性和方法
    2)父类的构造函数和析构函数有没有被继承到子类中?
        父类的构造函数和析构函数是没有被继承到子类中
    3)父类的构造函数和析构函数与子类的构造函数和析构函数的调用时机?
        单继承:
            先调用父类的构造,再调用子类的构造;先调用子类的析构,再调用父类的析构;
        多继承:
            先调用先继承的父类的构造,后调用后继承的父类的构造,再调用子类的构造;先调用子类的析构,再调用后继成的父类的析构,再调用先继承的父类的析构
    4)子类中有其他类的对象,现在的类的的调用时机?
        先调用父类的构造,再调用的其它类的构造,最后调用子类的构造;先调用子类的析构,再调用其他类的析构,最后调用父类的析构;
    5)如果父类构造函数携带参数,子类如何实例化对象?
        子类采用构造函数初始化列表的形式解决

4、虚继承
    使用vritual关键字结合继承权限去继承父类,称之为“虚继承”
格式:
    class  子类  : virtual   继承权限   父类   //虚继承
    {

    }
    或
    class  子类  :  继承权限  virtual   父类   //虚继承
    {

    }    

5、抽象类
    现实世界中有些事物是不能被实例化具体的对象,就可以用抽象类来描述
    抽象类只是描述具备哪些方法,具体实现要在子类中
虚函数:
    成员函数返回值前用关键字virtual来进行声明,表示该函数是一个虚函数
    例如:
        vritual   void  function() //虚函数
        {

        }
纯虚函数:
    令虚函数等于0,就表示该函数是纯虚函数
    格式:
        virtual  函数返回值   函数名(参数列表)=0;//纯虚函数
    例如:
        virtual  void function()=0;  //表示function函数是纯虚函数
抽象类定义:
    继承关系的类中,如果父类中如果含有纯虚函数,表示该类是一个抽象类,抽象类只是用于描述该类具备哪些行为,但是不具体实现这些行为
    例如:
        动物类------人、狗、蛇等等
        (抽象类)
            动物类:
                跑---行为
            子类-人:
                跑---两只脚跑
            子类-狗:
                跑---四只脚跑
            子类-蛇:
                跑---蠕动跑
            ......
例如:
class Animal
{
public:
    virtual void run() = 0;

};
class People :public Animal
{
public:
    virtual void run()
    {
        cout << "用两只脚跑" << endl;
    }
};
class Dog :public Animal
{
public:
    virtual void run()
    {
        cout << "用四只脚跑" << endl;
    }
};    

6、多态
    多态:
        多种形态或多种实现方法,C++中的多态是指一种接口(指的是父类接口),多种实现方法(指的是每个子类所实现的方法),即通过父类接口实现调用子类的多种方法
构成多态性的条件:
    1)具有继承关系的两个类
    2)父类指针或引用指向子类
    3)多种实现方法需要声明为虚函数
虚函数:
    成员函数返回值前用关键字virtual来进行声明,表示该函数是一个虚函数
    例如:
        vritual   void  function() //虚函数
        {

        }
虚函数表(虚表):
    用于存放类中的虚函数,每一个类都有自己独立的虚表(前提是有虚函数),并且每一个类的对象对于该类的虚表都是共享的
    有虚表指针指向虚表:vptr
    虚函数表是在编译时就建立

(1)静态绑定(静态联编)
    是指函数或表达式的地址,在编译时就已经确定
    根据对象的类型确定成员的调用地址
    例子:
        函数重载
        模板
(2)动态绑定(动态联编)
    是指函数或表达式的地址,在运行时才确定
    例子:
        多态
    根据指向的地址的对象的类型来确定成员的调用地址

7、虚析构函数
    为什么要提出虚析构函数?解决资源(子类)得不到释放的问题
    面试题:
        如果父类的析构函数不是虚函数,会带来(引起)什么问题?
        带来的问题:资源(子类)得不到释放的问题
        解决:将父类的析构函数声明为虚析构函数
虚析构函数:
    析构函数用vritual关键字来进行修饰,表示析构函数是虚析构函数
    前提:
        父类的指针或引用指向子类时
格式:
    virtual   ~类名()
    {
    }
例如:
    virtual  ~People()//虚析构函数
    {

    }    
8、限制构造函数
    限制对象的生成(创建)
    将构造函数放置在protected或private修饰符下,用于限制对象的生成


五、运算符重载
    是指赋于基本运算符新的运算,使之能应用于自定义的类型的运算(类类型),实际上是将运算符强制修饰为函数的形式
    例如:
        C语言:
            运算符:+
                10+20  //实现两个数据(基本的数据类型)相加
                10.5+20

        C++:
            运算符:+
                People+Animal  //People类类型、Animal类类型
                Peoson+Test

运算符重载: 本质上是给类定义运算操作,将类运算符强制修饰为函数(operator),将类的运算符操作变成函数操作。
可以被重载的运算符:
算术运算符:+、-、*、/、%、++、--
位操作运算符:&、|、~、^(位异或)、>(右移)
逻辑运算符:!、&&、||
比较运算符:<=、>=、等等
赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、>=
其他运算符:[]、()、->、,、new、delete、new[]、delete[]、*指针运算符
注意事项:
A、除成员访问运算符“.”、作用域运算符“::”、sizeof运算符和三目运算符“?:”以外,C++中的所有运算符都可 以重载(其中“=”和“&”不必用户重载)
B、重载运算符限制在C++语言中已有的运算符范围内的允许重载的运算符之中,不能创建新的运算符
C、运算符重载的实质是函数重载,遵循函数重载的选择原则
D、重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符操作数的个数及语法结构
E、运算符重载不能改变该运算符用于内部类型对象的含义
F、运算符重载是针对新类型数据的实际需要对原有运算符进行的适当的改造,重载的功能应当与原有功能相类似,避免没有目的地使用重载运算符
G、重载运算符的函数不能有默认的参数,否则就改变了运算符的参数个数
H、重载的运算符只能是用户自定义类型,否则就不是重载而是改变了现有的C++标准数据类型的运算符的规则
I、运算符重载可以通过成员函数的形式,也可是通过友元函数,还可以是非成员非友元的普通函数。

1、成员函数运算符重载
运算符重载的格式:
关键字:operator
格式:
    函数返回值类型     operator     重载的运算符   ([参数列表])//运算符重载,可以将operator和重载的运算符看成是函数名
    {
        //代码块
    }
例如:
    void    operator   +   (int  b)
    {

    }

2、友元函数运算符重载
关键字:friend 、 operator
格式:
    friend   函数返回值类型   operator     重载的运算符   ([参数列表]);//运算符重载,可以将operator和重载的运算符看成是函数名
例如:
    friend    void    operator   +   (int  b);

3、普通函数运算符重载
关键字:operator
格式:
     函数返回值类型   operator     重载的运算符   ([参数列表]);//运算符重载,可以将operator和重载的运算符看成是函数名
例如:
    void    operator   +   (int  b,int c);  //重点:参数个数要与运算符需求的参数个数匹配

六、输入/输出流
输入/输出流类:iostream---------i  input(输入)    o output(输出)   stream:流
iostream:
    istream类:输入流类-------------cin:输入流类的对象
    ostream类:输出流类------------cout:输出流类的对象
    
2、输入流:
    数据是从键盘或显示器流向输入缓冲区中,最后刷新了再流向内存
输入流:istream
    istream实例化了cin对象
    重载了运算符:>>
    输入格式:
        cin>>变量1;
        cin>>变量1>>变量2>>变量3.........;
    原型:
        istream &cin >>基本的数据类型;
        istream &cin >>int;
        istream &cin >>char;
        .......
    注:
        如果需要一次性输入多个数据,那么多个数据需要用空格进行间隔
        另外需要输入回车,把输入的内容刷新到内存中
1、输出流:
    数据是从内存流向输出缓冲区,刷新时再从输出缓冲区流向终端或显示器
    缓冲区的大小:
        #define  BUFSIZ   512个字节
(1)格式
输出流:ostream
    ostream实例化了cout对象、cerr对象(发生一些错误就会调用cerr输出错误信息)、clog对象(输出一些日志信息)        
    重载了运算符:<<
    输出格式:
        cout<<数据1;
        cout<<数据1<<数据2<<数据3,........;
    原型:
    ostream类中:
        ostream &  operator  <<(int)
        {
            ostream cout;
            .....
            return  cout;
        }
        ostream &  operator  <<(char)
        {
        }
    ostream  &cout  <<  基本的数据类型;
    ostream  &cout  <<  int ;
    ostream  &cout  << char;
    ostream  &cout  << unsigned int;
    ostream  &cout  << char *;
    ostream  &cout  << const char *;
    ostream  &cout  << float;
    .........

注:
    1)当输出遇到endl时,会刷新输出缓冲区
    2)当流对象使用完或超出作用域时,也会刷新输出缓冲区
    3)当输出缓冲区装满时,也会刷新一次缓冲区

(2)采用格式化输出
C语言的格式化输出也支持:\n、\r、.......
十进制形式输出:<iomanip>
    dec:十进制
    oct:八进制
    hex:十六进制
    ....
#include <iostream>  
#include<string>  
#include <iomanip> //不要忘记包含此头文件  
using namespace std;  
int main()  
 {   
   int a;  
   cout<<"input a:";  
   cin>>a;  
   cout<<"dec:"<<dec<<a<<endl; //以上进制形式输出整数  
   cout<<"hex:"<<hex<<a<<endl; //以十六进制形式输出整数a  
   cout<<"oct:"<<setbase(8)<<a<<endl;//以八进制形式输出整数a  
   string pt= "China";         //pt指向字符串”China”  
   cout<<setw(10)<<pt<<endl; //指定域宽为10,输出字符串  
   cout<<setfill('*')<<setw(10)<<pt<<endl;//指定域宽10,输出字符串,空白处以“*”填充  
   double pi=22.0/7.0; //计算pi值  
   cout<<setiosflags(ios::scientific)<<setprecision(8);//按指数形式输出,8位小数  
   cout<<"pi="<<pi<<endl; //输出pi值  
   cout<<"pi="<<setprecision(4)<<pi<<endl;//改为4位小数  
   cout<<"pi="<<setiosflags(ios::fixed)<<pi<<endl;//改为小数形式输出,精度为4   
   cout<<"pi="<<fixed<<pi<<endl;//fixed确定小数点后精度为4   

cout.setf(ios::showbase); //设置输出时的基数符号  
   cout<<"dec:"<<a<<endl; //默认以十进制形式输出a  
   cout.unsetf(ios::dec); //终止十进制的格式设置  
   cout.setf(ios::hex); //设置以十六进制输出的状态  
   cout<<"hex:"<<a<<endl; //以十六进制形式输出a  
   cout.unsetf(ios::hex); //终止十六进制的格式设置  
   cout.setf(ios::oct); //设置以八进制输出的状态  
   cout<<"oct:"<<a<<endl; //以八进制形式输出a  
   cout.unsetf(ios::oct); //终止以八进制的输出格式设置  
   char *pt="China"; //pt指向字符串”china”  
   cout.width(10); //指定域宽为10  
   cout<<pt<<endl; //输出字符串  
   cout.width(10); //指定域宽为10  
   cout.fill('*'); //指定空白处以'*'填充  
   cout<<pt<<endl; //输出字符串  
   double pi=22.0/7.0; //计算pi值  
   cout.setf(ios::scientific);//指定用科学记数法输出  
   cout<<"pi="; //输出"pi="  
   cout.width(14); //指定域宽为14  
   cout<<pi<<endl; //输出"pi值  
   cout.unsetf(ios::scientific); //终止科学记数法状态  
   cout.setf(ios::fixed); //指定用定点形式输出  
   cout.width(12); //指定域宽为12  
   cout.setf(ios::showpos); //在输出正数时显示“+”号  
   cout.setf(ios::internal); //数符出现在左侧  
   cout.precision(6); //保留6位小数  
   cout<<pi<<endl; //输出pi,注意数符“+”的位置  
   return 0;   
}  
运行结果如下:   
inputa:34 (输入a的值)   
dec:34 (十进制形式)   
hex:22 (十六进制形)   
oct:42 (八进制形式)   
China (域宽为10)   
***** China (域宽为10,空白处以'*'填充)   
pi=3.14285714e+00 (指数形式输出,8位小数)   
pi=3.1429e+00) (指数形式输小,4位小数)   
pi=3.143 (小数形式输出,精度仍为4)   
pi=3.1429(fixed确定小数点后精度为4 )

  dec:21 (十进制形式)
    hex:Oxl5 (十六进制形式,以0x开头)
    oct:025 (八进制形式,以O开头)
    China (域宽为10)
    *****china (域宽为10,空白处以'*'填充)
    pi=**3.142857e+00 (指数形式输出,域宽14,默认6位小数)
    ****3.142857 (小数形式输㈩,精度为6,最左侧输出数符“+”)

七、异常
    异常:发生错误
    C++是一种容错机制,允许主动发生错误、主动捕获错误、主动去处理错误。
    处理流程:
        (1)主动产生异常,抛出异常
        (2)检测是否产生了异常
        (3)捕获异常并对该异常进行处理
1、throw关键字
    用于抛出异常,即主动产生异常
使用格式:
    throw   异常的类型 ;  //抛出该种类型的异常
2、try代码块
    用于检测是否产生异常
使用格式:
    try
    {
        //待检测的代码
    }
3、catch代码块
    用于捕获异常并处理异常
使用格式:
    catch(捕获的异常类型) //直接放置类型
    {
        //对异常进行处理
    }
注意事项:
    (1)try代码块后面需要紧跟着至少一个catch块,try与catch是同时出现的
    (2)try代码块后的catch块的捕获顺序是按照catch的先后顺序进行捕获    
    (3)try检测出有异常发生,但未用catch块对异常进行捕获,那么该异常会被往try...catch块的上一级进行捕获,如果上一级也没有捕获到,继续往上抛,直到main函数种都没有捕获该异常,那么会调用windows的terminate来终止应用程序
    (4)try...catch块可以允许嵌套,首先是内层的try..catch捕获异常,内层没有捕获到,外层的try..catch捕获异常,以此类推直到main函数种都没有捕获该异常,那么会调用windows的terminate来终止应用程序
    格式:
    try
    {
        try
        {
            ...
        }
        catch()
        {
        }
        ....
    }
    catch()
    {
    }
    ....
    (5)捕获所有异常,将捕获所有异常的catch块放其它catch块的最后面
    格式:
        catch(...) //表示捕获所有异常
        {

        }

4、标准异常
    C++已经封装好的异常,只要用户产生了这些异常,编译器会自动抛出异常信息,封装好的异常类:exception(是所有标准异常的父类或基类),如何查看产生了标准的异常:exception类中提供了what()方法
std::exception    该异常是所有标准 C++ 异常的父类。
std::bad_alloc    该异常可以通过 new 抛出。
std::bad_cast     该异常可以通过 dynamic_cast 抛出。
std::bad_exception     这在处理 C++ 程序中无法预期的异常时非常有用。
std::bad_typeid  该异常可以通过 typeid 抛出。
std::logic_error 理论上可以通过读取代码来检测到的异常。
std::domain_error      当使用了一个无效的数学域时,会抛出该异常。
std::invalid_argument 当使用了无效的参数时,会抛出该异常。
std::length_error      当创建了太长的 std::string 时,会抛出该异常。
std::out_of_range      参数超出有效范围 
std::runtime_error     理论上不可以通过读取代码来检测到的异常。
std::overflow_error  当发生数学上溢时,会抛出该异常。
std::range_error     当尝试存储超出范围的值时,会抛出该异常。
std::underflow_error  当发生数学下溢时,会抛出该异常。

5、自定义异常类
    需要继承异常的父类:exception,重写what方法
class MyException :public exception//继承异常的父类
{
public:
    MyException(const char* obj)
    {
        //this->error_string = obj;
        this->error_string = new char[20];
        strcpy_s(error_string, 20, obj);
    }
    const char* what()const
    {
        return this->error_string;
    }
    char* error_string;
};


八、模板:template
    泛型编程:
        是指数据的类型是广泛,任意的数据类型
    模板:可以将一个函数或类描述成一个模板,例如:画画,给一个人物模型上色彩,根据用户上的色彩是什么人物显示什么样的色彩
模板:函数模板和类模板
1、函数模板
关键字:template、class/typename
格式:
    template   <模板形参1,模板形参2,........>函数返回值   函数名   ([参数1,参数2,.......])
    {

    }
    template   <class T1,class T2,........>函数返回值   函数名   ([参数1,参数2,.......])
    {
        
    }
    template   <typename T1,typename T2,........>函数返回值   函数名   ([参数1,参数2,.......])
    {

    }    
注意:
    (1)template用于声明一个模板
    (2)typename/class来声明模板形参,模板形参是指传递给该函数的参数类型(模板形参就是该函数的参数类型),指定该函数里用的模板形参的类型
    (3)模板形参要与函数形参一一对应
    
函数模板的调用:
    与C/C++普通函数调用一致:
        格式:
            函数名(实参1,实参2);//隐式调用(模板形参)
        例如:
            sum(10,20);
    函数模板的显示调用(模板形参):
        格式:
            函数名 <数据类型1,数据类型2,.......>(实参1,实参2,......);
        例如:
            sum<int ,   char> (10,'a');
2、类模板
关键字:template、class/typename
格式:
    template  <模板形参1 , 模板形参2,非类型形参,......> class  类名
    {
        
    };
    template  <class T1 , class T2,int  sum,......> class  类名
    {
        
    };    
    template  <typename T1 , typename T2,int  sum,......> class  类名
    {
        
    };
注:
    (1)class T1/T2等是模板形参,int  sum:非类型形参
        非类型:是指实例化类的时候,不能传递类型,只能传递实参,非类型形参是整型:int\short\long等等,不能是字符串或浮点型等
    (2)<>里的classs用于声明模板形参,类名前的class用于声明一个类

实例化类模板:
格式:
    类名 <参数类型1,参数类型2,非类型实参,......>对象名 (构造函数实参1,构造函数实参2,....);
例如:
    People<int , int>people(10,20);//实例化模板类的对象
    People<int , int,10>people(10,20);//实例化模板类的对象 ,10是非类型形参的实参
    

九、智能指针
    (1)为什么要提出智能指针?
        实际开发中:
            1)用户开辟了堆空间,没有及时释放堆空间资源,可能会造成内存泄露
            2)用户开辟了堆空间,也及时释放了堆空间资源,但该空间其它对象还在使用,会出现程序崩溃的现象
        作用:
            用于帮助用户去管理堆空间
    (2)智能指针与普通指针有什么区别?
        智能指针体现出智能化(可以帮助用户自动管理堆内存空间),当引用计数机制等于0的时候,智能指针会自动释放所管理的堆空间资源
        在C++中智能指针它不是一个指针,他是一个类(模板类),该类重载了指针的运算,例如:->、*、++、--等等,形象的称呼“智能指针”
C++提供的智能指针有四个:用于管理裸指针申请的堆空间
    shared_ptr:共享指针
    weak_ptr:弱指针
    unique_ptr:唯一指针
    C++11标准舍弃:auto_ptr:自动指针

1、shared_ptr共享指针
    该指针可以允许其它多个智能指针一起管理同一块内存空间
    如何使用:
        创建共享指针,共享指针会有两个空间,一个空间是管理的堆空间,另外一个空间是存放计数值
        计数值:
            共享指针引入的引用计数机制,计数值里存放的是有多少个智能指针管理同一块堆空间
            即新增一个智能指针管理堆空间,那么引用计数+1,减少一个智能指针管理堆空间,那么引用计数-1
方法:
    use_count()//查看引用计数值
    注:多个共享指针使用同一个引用计数空间
    get()//获取所管理的堆空间的地址
    swap(shared_ptr&)//交换两个共享指针管理的空间
2、weak_ptr弱指针
    weak_ptr提出是辅助shared_ptr使用,使用shared_ptr会出现问题?
    问题:
        使用共享指针会造成资源被相互占用,而得不到释放的问题
    提出:
        弱指针来解决该问题
3、unique_ptr唯一指针
    称为“独占式指针”,用unique_ptr去管理空间,那么只允许一个智能指针管理一个空间

十、标准模板库(Standard  Template  Labrory):STL
容器:
    用于存放数据
    顺序表
    链表
    队列
    ...
1、vector(向量或数组)
    vector向量是一个动态数组,可以根据实际需要去扩充向量(数组)的大小
    C语言中的数组是一个静态数组,大小一旦给定,固定大小
    vector也重载了数组相关的运算符,例如:[]
    
使用该库的时候包含头文件:#include "vector"
vector实质上是一个模板类
创建向量:
    vector<T> vect1();//创建向量时空的向量
    vector<T>vect2(int n);//创建向量时指定向量的大小,并且向量中的数据被初始化为0
    vector<T>vect3(int n,T data);//创建向量时指定向量的大小,并且将向量中的数据初始化为data
    vector vect4=vect3;//用一个向量来初始化另外一个向量    
    .....    
方法:
vector<T>v1;     // 默认的初始化方式,内容为空
vector<T>v2(v1);   // v2是v1的一个副本
vector<T>v3(n, i)   // v3中包含了n个数值为i的元素
vector<T>v4(n);   // v4中包含了n个元素,每个元素的值都是0
(2)vector常用函数
empty():判断向量是否为空,为空返回真,否则为假
begin():返回向量(数组)的首元素地址
end(): 返回向量(数组)的末元素的下一个元素的地址
clear():清空向量
front():返回得到向量的第一个元素的数据
back():返回得到向量的最后一个元素的数据
size():返回得到向量中元素的个数
push_back(数据):将数据插入到向量的尾部
pop_back():删除向量尾部的数据 

增加函数:
void push_back(const T& x):向量尾部增加一个元素X
iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素x
iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据
删除函数:
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
void pop_back():删除向量中最后一个元素
void clear():清空向量中所有元素
迭代器:
    迭代器实质上也是一个类,在向量、队列中都存在迭代器,重载了指针的运算符:*、->、++、--等等
2、list(链表)
链表:
    是不能随机访问,不能向数组一样随机访问链表中的数据
    例如:不能通过符号“[]”、at运算符访问链表中的数据元素
(1)初始化list对象的方式
list L0;    //空链表
list L1(3);   //建一个含三个默认值是0的元素的链表
list L2(5,2); //建一个含五个元素的链表,值都是2
list L3(L2); //L3是L2的副本
list L4(L1.begin(),L1.end());    //c5含c1一个区域的元素[begin, end]。
(2)list常用函数
begin():返回list容器的第一个元素的地址
end():返回list容器的最后一个元素之后的地址
rbegin():返回逆向链表的第一个元素的地址(也就是最后一个元素的地址)
rend():返回逆向链表的最后一个元素之后的地址(也就是第一个元素再往前的位置)
front():返回链表中第一个数据值
back():返回链表中最后一个数据值
empty():判断链表是否为空
size():返回链表容器的元素个数
clear():清除容器中所有元素
insert(pos,num):将数据num插入到pos位置处(pos是一个地址)
insert(pos,n,num):在pos位置处插入n个元素num
erase(pos):删除pos位置处的元素
push_back(num):在链表尾部插入数据num
pop_back():删除链表尾部的元素
push_front(num):在链表头部插入数据num
pop_front():删除链表头部的元素
sort():将链表排序,默认升序
.....
3、队列(deque)
1. deque<T> deq; //默认构造形式
2. deque<T> d2(d1.begin(),d1.end()); //将d1中[begin,end)区间中的元素拷贝给本身。
3. deque(n,elem);  //构造函数将n个elem拷贝给本身
4. deque(const deque &deq);  //拷贝构造函数
5. deque& operator=(const deque &deq);  //重载等号操作符
6. assign(beg, end);  //将[beg,end)区间中的数据拷贝赋值给本身。
7. assign(n,elem); //将n个elem拷贝赋值给本身。
8. empty(); //判断容器是否为空
9. size(); //返回容器中的元素的个数
10. resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
                      //如果容器变短,则末尾超出容器长度的元素被删除。
11. resize(num,elem); //重新指定容器的长度为num,若容器变成,则以elem值填充新位置。
                           //如果容器变短,则末尾超出容器长度的元素被删除。
12. push_back(elem);  //在容器尾部添加一个数据
13. push_front(elem);  //在容器头部插入一个数据
14. pop_back();  //删除容器最后一个数据
15. pop_front();  //删除容器第一个数据
16. insert(pos,elem);  //在pos位置插入一个elem元素的拷贝,返回新数据的位置。
17. insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值
18. insert(pos,beg,end);  //在pos位置插入[beg,end)区间的数据,无返回值
19. clear();  //清空容器的所有数据
20. erase(beg,end);  //删除[beg,end)区间的数据,返回下一个数据的位置。
21. erase(pos); //删除pos位置的数据,返回下一个数据的位置。
22. at(int idx); //返回索引idx所指的数据
23. front(); //返回容器中第一个数据元素
24. back(); //返回容器中最后一个数据元素

十一、C++的新特性
1、新增long long类型
long类型通常表示一个32位整型
新增long long类型用于表示一个64位整型
注:
(1)C++标准定义中,特别注明long long类型表示的是至少为64位的整数类型
(2)C++又为long long类型添加两个字面量后缀,分别是LL(表示有符号)和ULL(表示无符号)
例如:
long long a=-156656464 LL //表示有符号
long long a=1566449494 ULL  //表示无符号
2、新增列表初始化
符号:{}
在C++98标准中,符号{}用于初始化数组、结构体等等;在C++11中,列表初始化不仅能应用于内置类型变量(数组、结构体等)还能用于自定义类型变量(例如类类型),也可以用于在new开辟的空间时,传递构造函数实参
例如:
初始化基本数据类型:
int  a={1};
int  a{1} ;  //这种直接省略符号“=”
初始化自定义类类型:
People people={1,2};
3、nullptr常量
在程序开发中,一般在定义指针的同时会完成初始化操作(防止出现野指针的情况),所以在指针的指向不明确的时候,都会将指针初始化为空指针
在C++98中:
int  * a= 0;  //以下两种都可以实现将指针赋为空
int  *a=NULL
底层代码:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
//以上可以看到NULL可能被定义为常量0,也可能被定义为无类型指针(void *)0,会出现二义性问题
在C++11中:
定义了nullptr表示指针空值常量
    定义了nullptr_t表示指针空值类型
4、范围for语句
格式:
for(element:range)
{
}
其中element是一个变量,range是一个序列,范围for循环会遍历range中的每一个元素,并将其赋值给element(如果需要对range进行写操作,则必须将element声明为引用),然后在执行循环体的代码
例如:
int arr[5]={1,2,3,4,5};
for(int &a : arr)
{
a*=2; //将arr中每一个元素进行乘以2操作
}

int arr[5]={1,2,3,4,5};
int sum=0;
for(int a : arr)
{
sum+=a;
}
5、使用auto类型
C++11新增auto类型可以实现
(1)在声明变量时根据初始化列表表达式自动推导该变量的类型
(2)声明函数时,可以自动推导函数的返回值类型
注:
使用auto时,不能解决所有的精度问题
使用auto时,不能与其他类型组合使用,例如:auto int a//是错误的
使用auto时,必须对变量进行初始化
6、将sizeof用于类成员
例如:
class People
{
public :
int a=10;
char buf[20];
void run();
}
People people;
sizeof(people)//用于计算类中的成员变量,不算函数
7、lambda表达式
lambda表达式,也称为匿名函数
语法原型:
[capture-list] (parameters) opt -> return_type {statement}
(1)[capture-list]
它是捕获列表,不能省略,如果捕获,则表示为[]
常见的捕获列表:
[]:
表示不捕获
[&]:
表示按引用捕获
[=]:
表示按值捕获所有父作用域内的局部变量
[this]:
捕获当前类中的this指针,表示lambda表达式也拥有当前类成员的权限
(2)(parameters)
它是Lambda表达式参数列表,类似于函数的参数列表一样
如果无参:则表示为()
如果有参:则表示为(int a , int b,....)
(3)opt
可选项,一般省略
(4)return_type
Lambda表达式返回值类型,可以省略,也可以不省略
如果省略,则由return语句的返回值类型确定
如果不省略,则可以加数据类型作为返回值即可
(5){statement}
表示Lambda表达式函数体,类似于函数体,即可以在这里面实现相关功能
(6)Lambda表达式的调用
原型:
返回值类型  标识符 = Lambda表达式;
标识符(实参1,实参2,.....)//调用Lambda表达式
例如:
int  func=[](int a , int b){
return a+b;
}
func(10 , 20); //调用Lambda表达式
8、explicit类型转换运算符
通过explicit将表达式声明为类型的显式转换,不能实现隐式转换
9、虚函数的override指示符
如果虚函数用override关键字进行声明,表示该函数是重写了基类的同名虚函数
例如:
父类:
class Father
{
public:
virtual  void function();
}
class Son :public Father
{
public:
virtual void function()override; //表示该虚函数是重写了父类的虚函数function函数
}
10、通过定义类或虚函数为final来阻止继承
使用关键字final修饰来,表示该类禁止被继承
例如:
类:
class Father final
{

}
class Son :public Father //报错,因为Father禁止被继承
{

}
虚函数:
class Father 
{
public:
virtual void function()final
{
}
}
class Son :public Father 
{
public:
virtual void function()//报错,function函数禁止被继承到子类
{
}
}

   

总结:
    1)编译器不会为引用变量不会额外的开辟内存空间,使用的是原来的内存空间
    2)引用一旦存在就必须进行初始化的工作    

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值