文章目录
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.继承方式展开可变参数模板类:
- 可变参数模板声明
- 递归继承模板类
- 边界条件
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.模板递归和特例化方式展开参数包
- 变长模板声明
- 变长模板类定义
- 边界条件
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;
};