C++11的标准已经确定,除了增加了不少库函数外,在语法方便也得到了许多增强。其中如下几个语法就是我比较喜欢的:
自动类型推导auto
现在c++终于在编译器级别支持类似C#的var关键字了,在c++里的关键字是auto,基本用法如下:
auto i = 0; //int
auto c = ‘c‘; //char
auto s = "hello world"; //const char*
auto关键字的一个很直观的好处是我们可以简化stl容器遍历里的那个iterator了:
for(auto it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
Lambda 表达式
Lambda 表达式的主要用来构造匿名函数,它可以替换绝大部分场景的仿函数(感觉把刚刚引入STL库的std::bind也顺手给秒了),并且有更好的可读性。一个简单的示例如下:
auto k = [](int x, int y)
{ return x + y; };
cout << k(3, 2) << endl;
可以看到,它的基本语法形式为: [capture] (parameters) {body},后两部分和C#的匿名函数的语法非常,但最前面的 [capture] 的作用是什么呢?它是用来引用表达式外的局部变量的,例如:
int i1 = 0, i2 = 3;
auto k = [&i1, &i2] () { i1 = 3; i2 = 5; };
cout << i1 << " " << i2 << endl;
除了是前面所述的普通局部变量外,还可以是如下特殊符号:
- = 所有局部变量,以按值的方式传递(包括this指针)
- & 所有局部变量,以按引用的方式传递(包括this指针)
- this this指针
Range-based for-loop
这个其实就是类似C#里面的foreach,不过它并没有引入新关键字,而是直接用的for
int p[8] = {2, 3, 5, 7, 11, 13, 17, 19};
for (auto& i: p)
{
printf("%d ", i);
}
除了支持数组外,它也支持stl中的迭代器遍历,for_each函数基本上可以下岗了。至于它的原理,可以参考这篇文章。
枚举类
在C语言中,枚举等同于一个数字常量,编译器并没有对它做过多的处理,在C++11中,引入了enum class以替换枚举,它的定义方式如下:
enum class Color { Red, Blue};
enum class Fruit { Banana, Apple};
除了多加了一个class外,没有别的变化,但它定义的枚举功能和C#中的枚举相似。和C语言的传统枚举相比,主要有如下两个区别:
- 强类型的语法检查
- 枚举名称只需要在class范围内唯一
强类型的语法检查可以有效防止枚举之间的非法转换和比较,Color::Red == Fruit::Banana之类的判断无法编译通过。
而枚举名称只需要在class范围内唯一则有效缩短了枚举的长度,对于Color枚举,在C语言中,为了防止歧义和命名冲突,往往需要定义为Color_Red、Color_Blue的形式。
静态断言static_assert
静态断言主要提供了在代码中实现编译期可以确定的断言,如果出错则直接以编译错误的形式显示出来,从而加强程序的健壮性。这个其实就是以前的boost.static_assert,不过在编译器的支持下变得更加友好了。示例如下:
static_assert(sizeof(int) == 4, "int needs to be 4 bytes to use this code");
密闭类和密闭方法
C++11中也引入了类似C# seal关键字的方式实现密闭类和密闭方法,以阻止对象继承、方法重载。不过它的关键字是final,和java类似。
final类
class Base final
{
};
class Derived : public Base //继承密闭类,语法错误
{
};
final方法
class Base
{
virtual void A() final;
};
class Derived : public Base
{
virtual void A(); //重写密闭方法,编译出错
};
显式覆盖
对于虚函数的重写,在c++ 11中可以通过关键字显式覆盖,从而获得更严格的语法检查。
class Base
{
virtual void A(float=0.0);
virtual void B() const;
virtual void C();
void D();
};
class Derived: public Base
{
virtual void A(int=0) override; //定义不一致,编译错误
virtual void B() override; //返回类型不是const,编译错误
virtual void C() override; //正确
void D() override; //不是虚函数,编译错误
};
PS:我倒觉得这个语法检查应该默认就加上,通过关键字显式去掉检查,而不是像这样显式打开检查。万恶的向上兼容呀。
其它
其它还有几个语法我也很喜欢,如取消字符串转义、委托构造函数、deleted和defaulted成员函数、统一的初始化语法等,但这些在VC里面还不支持,无法实现跨平台开发,暂时就不介绍了。