C++11新特性
(1)对象构造的改良
在标准C++中,构造函数不能调用其它的构造函数;每个构造函数必须自己初始化所有的成员或是调用一个共用.的成员函数。基类的构造函数不能够直接作 为派生类的构造函数;就算基类的构造函数已经足够,每个派生的类仍必须实现自己的构造函数。类中non-constant的数据成员不能够在声明的地方被 初始化,它们只能在构造函数中被初始化。 C++11将会提供这些问题的解决方案。
C++11允许构造函数调用其他构造函数,这种做法称作委托或转接(delegation)。仅仅只需要加入少量的代码,就能让数个构造函数之间达成功能复用(reuse)。Java以及C♯都有提供这种功能。C++11语法如下:
class SomeType {
protected:
int number;
string name;
SomeType(int i,string&s):number(i),name(s){}
public:
SomeType(string& s):SomeType(1,s){ }
};
C++03中,构造函数运行退出代表对象构造完成;而允许使用转接构造函数的C++11则是以"任何"一个构造函数退出代表构造完成。使用转接的构造函数,函数本体中的代码将于被转接的构造函数完成后继续运行(如上例的PostInit())。若基底类使用了转接构造函数,则派生类的构造函数会在"所有"基底类的构造函数都完成后,才会开始运行。
(2)构造函数继承
C++11允许派生类手动继承基底类的构造函数,编译器可以使用基底类的构造函数完成派生类的构造。而将基类的构造函数带入派生类的动作,无法选择性地部分带入,要不就是继承基类全部的构造函数,要不就是一个都不继承(不手动带入)。此外,若牵涉到多重继承,从多个基底类继承而来的构造函数不可以有 相同的函数签名(signature)。而派生类的新加入的构造函数也不可以和继承而来的基底构造函数有相同的函数签名,因为这相当于重复声明。
class BaseClass
{
public:
BaseClass(int iValue){
cout<<"Base Constructor"<<endl;
};
};
class DerivedClass : public BaseClass
{
public:
using BaseClass::BaseClass;
};
此语法等同于DerivedClass声明一个DerivedClass(int)的构造函数。同时也因为DerivedClass有了一个继承而来的构造函数,所以不会有默认构造函数。
另一方面,C++11可以使用以下的语法完成成员初始化:
class SomeClass
{
public:
SomeClass() {}
explicit SomeClass(int iNewValue) : iValue(iNewValue) {}
private:
int iValue = 5;
};
若是构造函数中没有设置iValue的初始值,则会采用类定义中的成员初始化,令iValue初值为5。在上例中,无参数版本的构造函数,iValue便采用默认所定义的值;而带有一个整数参数的构造函数则会以指定的值完成初始化。
成员初始化除了上例中的赋值形式(使用"="(,也可以采用构造函数以及统一形的初始化(uniform initialization,使用"{}")。
(3)显式虚函数重载
在C++里,在子类中容易意外的重载虚函数。举例来说:
struct Base {
virtual void some_func();
};
struct Derived : Base {
void some_func();
};
Derived::some_func
的真实意图为何?程序员真的试图重载该虚函数,或这只是意外?这也可能是base
的维护者在其中加入了一个与Derived::some_func
同名且拥有相同签名的虚函数。
另一个可能的状况是,当基类中的虚函数的签名被改变,子类中拥有旧签名的函数就不再重载该虚函数。因此,如果程序员忘记修改所有子类,运行期将不会正确调用到该虚函数正确的实现。
C++11将加入支持用来防止上述情形产生,并在编译期而非运行期捕获此类错误。为保持向后兼容,此功能将是选择性的。其语法如下:
struct Base {
virtual void some_func(float);
};
struct Derived : Base {
// virtual void some_func(int) override; // 錯誤格式:Derive::some_func並沒有overrideBase::some_func
virtual void some_func(float) override; // OK:顯式改寫
};
编译器会检查基底类是否存在一虚拟函数,与派生类中带有声明override
的虚拟函数,有相同的函数签名(signature);若不存在,则会回报错误。
C++11也提供指示字final
,用来避免类被继承,或是基底类的函数被改写:
struct Base1 final { };
//struct Derived1 : Base1 { }; // 錯誤格式:classBase1已標明為final
struct Base2 {
virtual void f() final;
};
struct Derived2 : Base2 {
// void f(); // 錯誤格式:Base2::f已標明為final
};
以上的示例中,virtual void f() final;
声明一新的虚拟函数,同时也表明禁止派生函数改写原虚拟函数。
override
与final
都不是语言关键字(keyword),只有在特定的位置才有特别含意,其他地方仍旧可以作为一般指示字(identifier)使用。
(4)Lambada 表达式
C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性,建议买一本书看看。
很多语言都提供了 lambda 表达式,如 Python,Java 8。lambda 表达式可以方便地构造匿名函数,如果你的代码里面存在大量的小函数,而这些函数一般只被调用一次,那么不妨将他们重构成 lambda 表达式。
C++11 的 lambda 表达式规范如下:
[ capture ] ( params )mutable exception attribute -> ret { body } (1)
[ capture ] ( params )-> ret { body } (2)
[ capture ] ( params ) {body } (3)
[ capture ] { body } (4)
其中
(1) 是完整的 lambda 表达式形式,
(2) const 类型的 lambda 表达式,该类型的表达式不能改捕获("capture")列表中的值。
(3)省略了返回值类型的 lambda 表达式,但是该 lambda 表达式的返回类型可以按照下列规则推演出来:
如果 lambda 代码块中包含了return 语句,则该 lambda 表达式的返回类型由 return 语句的返回类型确定。
如果没有 return 语句,则类似 voidf(...) 函数。
(4) 省略了参数列表,类似于无参函数 f()。
mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。
exception 说明 lambda 表达式是否抛出异常(noexcept),以及抛出何种异常,类似于voidf() throw(X, Y)。
attribute 用来声明属性。
另外,capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表,具体解释如下:
[a,&b] a变量以值的方式呗捕获,b以引用的方式被捕获。
[this] 以值的方式捕获 this 指针。
[&] 以引用的方式捕获所有的外部自动变量。
[=] 以值的方式捕获所有的外部自动变量。
[] 不捕获外部的任何变量。
std::vector<int> c { 1,2,3,4,5,6,7 };
int x = 5;
c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; } ),c.end());
std::cout << "c: ";
for (auto i: c) {
std::cout << i<< ' ';
}
std::cout << '\n';
// the type of a closure cannot be named, but can beinferred with auto
auto func1 = [](int i) { return i+4; };
std::cout << "func1: " << func1(6) << '\n';
// like all callable objects, closures can be captured instd::function
// (this may incur unnecessary overhead)
std::function<int(int)> func2 = [](int i) { return i+4; };
std::cout << "func2: " << func2(6) << '\n';
auto f = [] (int x, int y) { return x + y; };
cout << f(21, 12) << endl;
return 0;
(5)std::function
我们知道,在C++中,可调用实体主要包括函数,函数指针,函数引用,可以隐式转换为函数指定的对象,或者实现了operator()的对象(即C++98中的functor)。C++0x中,新增加了一个std::function对象,std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(我们知道像函数指针这类可调用实体,是类型不安全的)。我们来看几个关于function对象的例子:
#include <functional>
std::function< size_t (const char*) > print_func;