设为首页 加入收藏

TOP

c++11深入学习(二)
2015-07-20 17:19:29 来源: 作者: 【 】 浏览:9
Tags:深入 学习
非成员的begin和end函数。用法如下:

?

?

1 sort(begin(v), end(v));

2 sort(begin(a), end(a));

?

?

显式虚函数重载

?

在引入C++ 11之前,基类和派生类中的虚函数很容易产生错误使用的情况。比如:

?

a、基类添加了一个虚函数,但该虚函数与派生类中的某个已有普通函数相同。

?

b、派生类添加了一个普通函数,但该函数与基类中的某个已有虚函数相同。

?

为了避免这些情况,在C++ 11中可以使用override来显式地表明需要进行虚函数重载。比如:

?

?

1 class Base

2 {

3 virtual void some_func(float);

4 };

5

6 class Derived : public Base

7 {

8 virtual void some_func(int) override; // 将产生编译错误

9 virtual void some_func(float) override; // 正确

10 };

?

?

?

C++ 11中还引入了final指示符,用于防止类或接口被继承。比如:

?

?

?

1 class Base1 final { };

2 class Derived1 : public Base1 { }; // 将产生编译错误

3 class Base2

4 {

5 virtual void f() final;

6 };

7 class Derived2 : public Base2

8 {

9 void f(); // 将产生编译错误

10 };

?

?

C++ 03中,可以使用typedef给模板类指定一个新的类型名称,但却不能给类模板指定别名。比如:

?

1 template< typename first, typename second, int third>

2 class SomeType; template< typename second>

3 typedef SomeType TypedefName; // 在C++ 03中是不合法的

?

?

?

无限制的union

?

在C++ 03中,并非任意的数据类型都能做为union的成员。比方说,带有non-trivial构造函数的类型就不能是 union 的成员。在C++ 11中,移除了所有对union的使用限制,除了其成员仍然不能是引用类型这种情况。

?

?

?

?

1 struct point

2 {

3 point() {}

4 point(int x, int y): m_x(x), m_y(y) {}

5 int m_x, m_y;

6 };

7 union

8 {

9 int z;

10 double w;

11 point p; // 在C++ 03中不合法;在C++ 11中合法

12 };

?

在C++ 11中,允许sizeof运算符作用在类型的数据成员上,而无须明确的对象。在C++ 03中,这是不允许的,会导致编译错误。比如:

1 struct SomeType { OtherType member; };

2 sizeof(SomeType::member); // 在C++ 03中不合法;在C++ 11中合法

?

新的算法

?

C++ 11中新增了一些比较实用的算法。比如all_of、any_of、none_of、copy_n、copy_if和iota等。参考代码如下:

?

?

1 int a[5] = {-2, -1, 0, 1, 2};

2 auto funIsPositive = [](int v){return v>0;};

3 bool bRet = all_of(a, a+5, funIsPositive); // false

4 bRet = any_of(a, a+5, funIsPositive); // true

5 bRet = none_of(a, a+5, funIsPositive); // false

6 int b[5] = {0};

7 copy_n(a, 5, b); // 将a开始的5个元素拷贝到b中

8 copy_if(a, a+5, b, funIsPositive); // 将1, 2两个数拷贝到b中

9 iota(a, a+5, 10); // a中的每个元素加10

?

?

泛化的常数表达式

?

C++ 03中本来就已经具有常数表示式的概念,比如:3+5,6*7等。常数表示式对编译器来说是优化的机会,编译器常在编译期运行它们并且将值存入程序中。同样地,在许多场合下,C++规范要求使用常数表示式。比如数组大小、枚举值等。

?

然而,常数表示式总是在遇到了函数调用时就终结。比如:

1 int GetFive() { return 5; }

2 int some_value[GetFive() + 5]; // 不合法

?

?

C++ 11引进关键字constexpr允许用户保证函数是编译期常数。比如:

1 constexpr int GetFive() { return 5; }

2 int some_value[GetFive() + 5];

?

?

?

?

?

C++ 11中引入的一个非常重要也是比较难于理解的新特性就是完美转发(Perfect Forwarding)。完美转发中有两个关键词:“转发”和“完美”。

我们先来看第一个关键词“转发”,那么在C++中,“转发”表示什么含义呢?转发通常用在模板编程中,假设有一个函数F(a1, a2, ..., an),如果存在另一个函数G(a1, a2, ..., an),调用G相当于调用了F,则我们说函数G将a1, a2, ..., an等参数正确地转发给了函数F。再来看第二个关键词“完美”,“完美”转发是相对于其他转发方案而言的。在目前已提出的7种转发方案中,只有完美转发能够正确地实现转发的语义,其他方案都存在这样或那样的问题。下面一一进行介绍。

转发方案一:使用非常量左值引用。考虑下面的代码。

?

?

?

?

1 void F(int a)

2 {

3 cout << a << endl;

4 }

5

6 template

7 void G(A &a)

8 {

9 F(a);

10 }

?

?

?

使用非常量左值引用时,我们可以调用F(10),但无法调用G(10),即我们无法接收非常量右值的参数。

?

?

?

转发方案二:使用常量左值引用。考虑下面的代码。

?

?

?

?

1 void F(int &a)

2 {

3 cout << a << endl;

4 }

5

6 template

7 void G(const A &a)

8 {

9 F(a);

10 }

?

?

?

使用常量左值引用时,函数G可以接收任意类型的值作为参数,包括非常量左值、常量左值、非常量右值和常量右值。但当F的参数类型为非常量左值引用时,我们无法将一个常量左值引用转发给一个非常量左值引用。

?

?

?

转发方案三:使用非常量左值引用 + 常量左值引用。考虑下面的代码。

?

?

?

?

1 template

2 void G(A &a)

3 {

4 F(a);

5 }

6

7 template

8 void G(const A &a)

9 {

10 F(a);

11 }

?

?

?

综合前面两种方案的分析结果,可以得出这种方案相当于对函数G进行了重载,此时可以接收任意类型的值作为参数,也可以顺利地实现转发。但由于使用了常量和非常量两种形式的重载,当参数的个数N较大时,需要重载的函数会呈指数级增长(2的N次方),因此这种方案实际上是不可取的。

?

?

?

转发方案四:使用常量左值引用 + const_cast。

?

?

1 template

2 void G(const A &a)

3 {

4 F(const_cast(a));

5 }

?

这种方案克服了方案二的缺点,现在可以将常量左值引用转发给非常量左值引用了。但

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Leetcode_Longest Common Prefix 下一篇Leetcode_Palindrome Number

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·怎样用 Python 写一 (2025-12-27 02:49:19)
·如何学习python数据 (2025-12-27 02:49:16)
·想要自学数据分析, (2025-12-27 02:49:14)
·Java 集合框架 - 菜 (2025-12-27 02:19:36)
·Java集合框架最全详 (2025-12-27 02:19:33)