c++11新特性

1、泛化常量表达式 constexpr

C++中常量表达式在遇上了函数调用或是对象构造函数时就终结。所以像是以下的例子是不合法的

int get_five() {return 5;}

int value[get_five() + 5];// 预产生10个整数的数组。C++中非法

C++11引进关键字 constexpr 允许使用者保证函数或是对象构造函数是编译期常数。以上的例子可以被写成像是下面这样

constexpr int get_five() {return 5;}

int value[get_five() + 5];// 预产生10个整数的数组。C++中合法

注意:

1. 函数的返回值不能是void 2.函数内容必须是“return expr”的形式 3.在引用被取代后,必须是个常数表达式

2、类型推导 auto

解决类型无法判断的问题,如模板;减少冗余代码

3、nullptr

C++11 引入了新的关键字来代表空指针常数:nullptr,将空指针和整数 0 的概念拆开。 nullptr 的类型为nullptr_t,能隐式转换为任何指针或是成员指针的类型,也能和它们进行相等或不等的比较。

nullptr不能隐式转换为整数,也不能和整数做比较。

4、基于范围的循环

map<string, int> m{{"a", 1}, {"b", 2}, {"c", 3}}; 
for (auto p : m
) {  
   cout<<p.first<<" : "<<p.second<<endl

}

5、overridefinal关键字

当基类中的虚函数的签名被改变,子类中拥有旧签名的函数就不再重载该虚函数。因此,如果程序员忘记修改所有子类,运行期将不会正确调用到该虚函数正确的实现

C++11 将加入支持用来防止上述情形产生,并在编译期而非运行期捕获此类错误。其语法如下

struct Base {

    virtual void some_func(float);

};

struct Derived : Base {

    virtual void some_func(int) override;   // 错误格式: Derive::some_func 並沒有 override Base::some_func

    virtual void some_func(float) override; // OK:显示改写

};

C++11 也提供指示字final,用来避免类被继承,或是基底类的函数被改写

struct Base1 final { };

struct Derived1 : Base1 { }; // 错误格式: class Base1 已标明为 final

 struct Base2 {

    virtual void f() final;

};

struct Derived2 : Base2 {

    void f(); // 错误格式: Base2::f 已标明为 final

};

6、明确禁止和明确删除的特殊成员函数

C++11 允许显式地表明采用或拒用编译器提供的内置函数。例如要求类带有默认构造函数,可以用以下的语法

struct SomeType

{

  SomeType() = default; // 預設建構式的顯式聲明

  SomeType(OtherType value);

};

另一方面,也可以禁止编译器自动产生某些函数。如下面的例子,类不可复制

struct NonCopyable

{

  NonCopyable & operator=(const NonCopyable&) = delete;

  NonCopyable(const NonCopyable&) = delete;

  NonCopyable() = default;

};

7、智能指针

能自动释放内存的智能指针包括以下几种:
unique_ptr: 如果内存资源的所有权不需要共享,就应当使用这个(它没有拷贝构造函数),但是它可以转让给另一个unique_ptr(存在move构造函数)。
shared_ptr如果内存资源需要共享,那么使用这个(所以叫这个名字)。
weak_ptr: 持有被shared_ptr所管理对象的引用,但是不会改变引用计数值。它被用来打破依赖循环(想象在一个tree结构中,父节点通过一个共享所有权的引用(shared_ptr)引用子节点,同时子节点又必须持有父节点的引用。如果这第二个引用也共享所有权,就会导致一个循环,最终两个节点内存都无法释放)

int main( )

{

    std::shared_ptr<double> p_first(new double) ;

    {

        std::shared_ptr<double> p_copy = p_first ;

        *p_copy = 21.2;

    }  // 此时 'p_copy' 会被销毁,但动态分配的double不会被销毁

    return 0;  // 此时 'p_first' 会被销毁,动态分配的double也会被销毁(因为不再有指针指向它

}

8、 lambda 函数

在标准 C++,特别是当使用 C++ 标准程序库算法函数诸如 sort 和 find,使用者经常希望能够在算法函数调用的附近定义一个临时的部函数(又称谓词函数,predicate function)。C++11 对 lambda 的支持可以解决上述问题

一个 lambda 函数可以用如下的方式定义:

vector<int> iv{5, 4, 3, 2, 1}; 

int a = 2, b = 1;  

for_each(iv.begin(), iv.end(), [b](int &x){cout<<(x + b)<<endl;}); // (1)  

for_each(iv.begin(), iv.end(), [=](int &x){x *= (a + b);});     // (2)  

for_each(iv.begin(), iv.end(), [=](int &x)->int{return x * (a + b);});// (3)

Lambda的语法如下[函数对象参数](操作符重载函数参数)->返回值类型{函数体}

a、[]内的参数指的是Lambda表达式可以取得的变量。

[]  // 沒有定义任何参数。使用未定义参数会导致错误

[x, &y] // x 以传值方式传入,y以引用方式传入

[&]   // 任何被使用到的外部变量皆引用方式传入

[=]   // 任何被使用到的外部变量都是以传值方式传入

[&, x]   // x 显示地以传值方式加以引用。其余变量已引用方式传入

[=, &z]   // z 显示地以引用方式传入。其余变量以传值方式传入

b、()内的参数是每次调用函数时传入的参数。

c、->后加上的是Lambda表达式返回值的类型,如(3)中返回了一个int类型的变量

9、非成员begin()end()

C++11新加入标准库的功能,既能提高了代码一致性,还有助于更多地使用泛型编程。它们和所有的STL容器兼容。更重要的是,他们是可重载的。所以它们可以被扩展到支持任何类型。对C类型数组的重载已经包含在标准库中了

int arr[] = {1,2,3};

std::for_each(std::begin(arr), std::end(arr), [](int n) {std::cout << n << std::endl;});

auto is_odd = [](int n) {return n%2==1;};

auto pos = std::find_if(std::begin(arr), std::end(arr), is_odd);

if(pos != std::end(arr))

std::cout << *pos << std::endl;

10、右值引用和 move 语义

C++11 增加一个新的非常数引用(reference)类型,称作右值引用(R-value reference),标记为T &&。右值引用所引用的临时对象可以在该临时对象被初始化之后做修改,这是为了允许 move 语义。
move功能是将一个左值强制转化为右值引用,继而我们可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue)

template<class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
 
typedef typename remove_reference<T>::type&& RvalRef;
  return
static_cast<RvalRef>(a);
}

通过重载右值引用的函数,用户一旦发现这是一个右值引用,那么就可以不实现拷贝,而是实现转移。所谓转移,就是可以将资源 ( ,系统对象等 ) 的所有权从一个对象(通常是匿名的临时对象)转移到另一个对象,从而减少对象构建及销毁操作,提高程序效率

11、变长参数的模板

C++11 加入新的表示法,允许任意个数、任意类别的模板参数,不必在定义时将参数的个数固定

template<typename... Values> class tuple;

模板类 tuple 的对象,能接受不限个数的 typename 作为它的模板形参

class tuple<int, std::vector<int>, std::map<std::string, std::vector<int>>> someInstanceName;

12、模板别名

先弄清楚“模板”和“类型”本质上的不同。class template (类模板,是模板)是用来产生 template class (模板类,是类型)。 在标准 C++,typedef 可定义模板类一个新的类型名称,但是不能够使用 typedef 来定义模板的别名。举例来说

template< typename first, typename second, int third>

class SomeType;

template< typename second>

typedef SomeType<OtherType, second, 5> TypedefName; // 在C++是不合法的

这不能够通过编译

为了定义模板的别名,C++11 将会增加以下的语法

template< typename first, typename second, int third>

class SomeType;

template< typename second>

using TypedefName = SomeType<OtherType, second, 5>;

using 也能在 C++11 中定义一般类型的别名,等同 typedef

typedef void (*PFD)(double); 

using PFD = void (*)(double); 

13、委托构造函数

在c++11中有一个新特性,就是委托构造函数。委托构造函数可以使用当前类的其他构造函数来帮助当前构造函数初始化。换而言之,就是可以将当前构造函数的部分(或者全部)职责交给本类的另一个构造函数。

    我们先看看委托构造函数与普通构造函数的相同点与不同点。

相同点:
    两者都有一个成员初始值列表与一个函数体
不同点:
    委托构造函数的成员初始值列表只有一个唯一的参数,就是构造函数(当然不能是当前的构造函数)    
         当被委托的构造函数的函数体中如果有代码,那么会先执行完函数体的代码,才会回到委托构造函数。在这里我们可以理解为一次函数调用(当然两者还是有些区别的)。我们来看看示例代码
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值