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"};
};

列表初始化:

struct Test{
  int a;
  int b;
  string c;
};

int main()
{
   struct Test t = {1,2,"mike"};
}

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

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

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

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

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
}

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

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
}

6.强类型的枚举

enum S {ok,no};//报错,ok重定义
enum S1 {ok,no};

S flag = ok;

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

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

enum class S {ok,no};//报错,ok重定义
enum class S1 {ok,no};

S flag = S::ok;

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

enum class S :char{ok,no};

7.常量表达式

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

int Get()
{ return 3}
constexpr int get()
{ return 3}
int main()
{
   enum S { e1 = Get()}//报错,Get()非常量
   enum S { e1 = get()}//编译通过
}

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;//新特性中简化了上面那一步
};

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

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;
};

10.类型别名

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

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;
};//允许编译通过

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;
}

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


void func()//递归终止条件,没有参数
{
}
template<typename T1,typename ...T2>//T为模板参数包
void func(T1 first,T2...second)//args为函数参数包
{
  func(second...);
}

非递归方式展开:

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.继承方式展开可变参数模板类:

  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<> {};//类型为空时结束继承,边界条件

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;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值