• C++新特性笔记(2)


    1.类中成员变量初始化

    C++11中可以直接给类成员赋值初始化,使用等号或者大括号

    class A
    {
    public:
       A(int a):a(a){}
    private:
     int a;
    };
    
    class B
    {
       public:
       int data = 1;
       int data2{2};
       A a{3};
       string name{"mike"};
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    列表初始化:

    struct Test{
      int a;
      int b;
      string c;
    };
    
    int main()
    {
       struct Test t = {1,2,"mike"};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    C++11中允许内置类型进行初始化如:

    int main()
    {
       int a ={1};
       int b{2};
       int c[]{1,2,3};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    C++11中允许内置类型进行初始化可以防止类型收窄:

    int a = 1024;
    char b = a;//编译不报错,但是输出错误
    char c = {a};//编译报错,提示类型收窄
    
    • 1
    • 2
    • 3

    2.基于范围的for循环

    int a[] = {1,2,3,4,5,6,7,8};
    for(auto s:a)
    {
      cout<<s<<",";//输出1,2,3,4,5,6,7,8
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    但是容器范围要确定,否则无法使用

    3.静态断言

    assert()//如果条件为真就继续执行,如果为假中断程序,提示错误,在运行阶段执行。

    static_assert()可以用于在编译阶段对断言进行测试,更早报告错误,降低开发成本,减少运行时的开销。

    static_assert(常量表达式,“提示的字符串”);

    4.noexcept修饰符

    C++11使用noexcept代替了throw(),表示不抛出任何异常

    5.nullptr

    解决0和NULL二义性问题:

    void fun(int a)
    {cout<<"A"<<endl;}
    void fun(int* p)
    {cout<<"B"<<endl;}
    int main()
    {
      fun(NULL);//输出A,因为NULL就是0的宏定义
      fun(nullptr);//输出B
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6.强类型的枚举

    enum S {ok,no};//报错,ok重定义
    enum S1 {ok,no};
    
    S flag = ok;
    
    • 1
    • 2
    • 3
    • 4

    因为枚举定义的枚举项(ok,no)相当于该作用域内的全局变量,不能再次被定义。

    强类型的枚举,在enum后加上class或struct

    enum class S {ok,no};//报错,ok重定义
    enum class S1 {ok,no};
    
    S flag = S::ok;
    
    • 1
    • 2
    • 3
    • 4

    强类型的枚举还可以指定成员变量的类型

    enum class S :char{ok,no};
    
    • 1

    7.常量表达式

    常量表达式主要是允许一些计算发生在编译阶段,节省计算机性能

    int Get()
    { return 3}
    constexpr int get()
    { return 3}
    int main()
    {
       enum S { e1 = Get()}//报错,Get()非常量
       enum S { e1 = get()}//编译通过
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    constexpr限制:函数中只能有一个return语句;函数必须有返回值;在使用前必须已有定义;return返回语句表达式中不能使用非常量表达式的函数、全局数据,且必须是一个常量表达式。

    8.继承构造

    基类的成员变量必须要进行初始化,那么派生类也需要对继承而来的成员变量初始化,C++新特性中简化了这一个步骤:

    
    class A{
    public:
    A(int x,int y):x(x),y(y)
    {
    }
    private:
    int x;
    int y;
    };
    
    class B{
     public:
     B(int x,int y):A(x,y)//继承的带参构造函数必须调用基类的构造函数初始化
     {
     }
    };
    
    class C
    {
      public:
      using A::A;//新特性中简化了上面那一步
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    继承构造不可以对默认构造函数、复制构造函数、移动构造函数使用,虚继承也不可以,并且不能初始化派生类成员变量

    9.委托构造函数

    委托构造一定要通过初始化列表方式

    class A{
     A():A(1,'a'){}
     A(int x):A(x,'a'){}
     A(char y):A(1,y){}
     A(int x,char y):a(x),b(y){}
     private:
     int a;
     char b;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    10.类型别名

    typedef int int32;//传统起别名方式
    using my_int = int;//C++11新方式
    
    • 1
    • 2

    11.函数模板的默认模板参数

    类模板的模板类型参数必须是从右往左,函数模板参数则没有要求,默认模板参数是C++11中才可以使用

    template<typename T1 , typename T2 = int>
    class A {
    public:
    	A(T1 a, T2 b) :a(a), b(b) {}
    	void print()
    	{
    		cout << a << endl;
    	}
    	T1 a;
    	T2 b;
    };//允许编译通过
    template<typename T1 = int , typename T2> //编译不通过,因为从左向右设置默认参数类型,T2还没赋默认参数类型,T1不能先赋
    class A {
    public:
    	A(T1 a, T2 b) :a(a), b(b) {}
    	void print()
    	{
    		cout << a << endl;
    	}
    	T1 a;
    	T2 b;
    };//允许编译通过
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    12.可变参数模板

    template<typename ...T>//T为模板参数包
    void func(T...args)//args为函数参数包
    {}
    
    int main()
    {
       func<int>(10);
       func<int,char>(1,'a');
       func<int,char*,char>(100,"abc",'a');
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    函数模板参数包的展开:
    可变参数的参数包由递归方式展开:

    
    void func()//递归终止条件,没有参数
    {
    }
    template<typename T1,typename ...T2>//T为模板参数包
    void func(T1 first,T2...second)//args为函数参数包
    {
      func(second...);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    非递归方式展开:

    template<typename T>
    void print(T tmp)
    {
       cout << tmp  <<endl;
    } 
    template<typename ...T>//T为模板参数包
    void func(T...args)//args为函数参数包
    {
       int arr[] = {{print(args),0}...};//劣势:只能一种类型
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    类模板参数包的展开:

    1.继承方式展开可变参数模板类:

    1. 可变参数模板声明
    2. 递归继承模板类
    3. 边界条件
    template<class ...T> class {};
    template<typename Head,class ..Tail>
    class A<Head,Tail...>:public A(Tail...)
    {
       public:
       A()
       {
          cout <<"type = "<<typeid(Head).name()<<endl;
       }
    }
    template<> class<> {};//类型为空时结束继承,边界条件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.模板递归和特例化方式展开参数包

    1. 变长模板声明
    2. 变长模板类定义
    3. 边界条件
    template<class ...T>
    class A{}
    
    template<typename first,class ..second>
    class A<first,second...>
    {
    public:
       static_const int val = first * A<second...>::val;
    };
    
    template<>
    class A<>
    {
    public:
       static_const int val = 1;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    使用Vscode创建一个C_Hello程序
    美团·阿里关于多模态召回的应用实践
    Backblaze 2022 Q3 硬盘故障质量报告解读
    Vue3-provide 和 inject 跨组件传递数据
    【Docker】Docker入门学习
    Selenium4+Python3系列(五) - 多窗口处理之句柄切换
    利用DownThemAll工具批量下载网页单一链接的数据
    【LINUX】使用Service服务开机自启动脚本或者指令
    Janus: Data-Centric MoE 通讯成本分析(2)
    Zookeeper经典应用场景实战
  • 原文地址:https://blog.csdn.net/weixin_44971209/article/details/126228889