[C/C++学习]之十七、C++11中我们需要关注的(一)

2014-11-24 07:11:01 · 作者: · 浏览: 0

前面的博客一只在说c++,现在来看一下c++新标准,在维基百科中已经给出了详细说明,可以去看一下。

C++11的设计目标是:

1.使得c++成为更好的适用于系统开发及库开发的语言。

2.使得c++成为更易于教学的语言。

3.保证语言的稳定性,以及和C++03及c语言的兼容性。

c++11 的增强点,主要包括:

1.通过内存模型,线程,原子操作等来支持本地并行编程

2.通过统一初始化表达式、auto、declytype、移动语义等来统一对泛型编程的支持。

3.通过constexpr,POD等更好地支持系统编程。

4.通过内联命名空间,集成构造函数和右值引用等,以更好地支持库的构建。

下面我们把特性里面涉及的名词来解释一下:

1、统一初始化表达式:

c++11用大括号统一了初始化。在c++11中,这种初始化方法叫做:初始化列表 initializer list

	int a[] {12, 22};
	vector
  
    a{ 1, 2, 3 };
	map
   
     a = { { 1, 1.0f }, { 2, 2.0f } };
   
  

在c++11中,我们可以通过以下几种形式来完成初始化的工作:

	int a = 1 + 1;
	int a = { 1 + 1 };
	int a{ 1 + 1 };
	int a(1 + 1);

2、就地声明:

在类中,我们直接使用等号来初始化静态成员常量的方式,就是就地初始化。如:

class a{
public:
	a() :b(0) {}
private:
	int b;
	const static int b = 0;
};

要注意的是,需要静态的常量成员。 还有一点就是需要整形或者枚举类型。

但是在我们c++11中,允许对非静态成员变量进行就地初始化:

class a{
	int b = 1;
	int c{ 2 };
};
要注意的是,这里不能使用圆括号进行就地初始化。

在类中会涉及到构造函数初始化列表的问题,他跟就地初始化并不冲突,但是构造函数初始化列表的效果总是优先于就地初始化。

3、自定义类初始化列表:

可以通过#include 头文件中的initializer_list类模板支持初始化列表。
下面来看一下对类、函数和操作符进行初始化的例子:

#include 
  
   
#include 
   
     #include 
    
      using namespace std; class C{ public: C(initializer_list
     
      > l, initializer_list
      
        m, initializer_list
       
         n) { auto i = l.begin(); for (; i != l.end(); ++i) { data.push_back(*i); } auto j = m.begin(); for (; j != m.end(); ++j) idx.push_back(*j); auto s = n.begin(); for (; s != n.end(); ++s) d.push_back(*s); } C & operator[](initializer_list
        
          l) { for (auto i = l.begin(); i != l.end(); ++i) { idx.push_back(*i); } return *this; } C & operator = (int v) { if (idx.empty() != true) { for (auto i = idx.begin(); i != idx.end(); ++i) { d.resize((*i > d.size())   *i : d.size()); d[*i - 1] = v; } idx.clear(); } return *this; } void Fun(initializer_list
         
           l) { for (auto i = l.begin(); i != l.end(); ++i) { cout << *i << " "; } cout << endl; } private: vector
          
           > data; vector
           
             idx; vector
            
              d; }; int main(void) { C ctr{ { { "s", 1 }, { "e", 2 } }, { 3, 4 }, { 5, 6 } }; ctr.Fun({ 1, 2 }); ctr.Fun({}); ctr[{2, 3, 4}] = 7; ctr[{1, 3, 4, 5}] = 2; };
            
           
          
         
        
       
      
     
    
   
  


4、auto类型

先来看一下代码:

#include 
  
   
using namespace std;

int main(void)
{
	auto name = "hello world \n";
	cout << name;

	char* name1 = "hello world \n";
	cout << name1;

	return 0;
}
  

根据上面的代码可以知道,auto和string的效果是一样的,是的,auto关键字要求编译器对变量name的类型进行自动推导。

在之前版本的C++中,auto的意思是具有自动存储期的局部变量,然而,一般情况下在函数里没有声明为static的变量总是具有自动储存期的局部变量。

在c++11中,auto声明变量的类型必须由编译器在编译时期推导得到。

5、declytype

declytype与auto类似,也可以进行类型推导,但是使用方式有一定区别。

declytype以一个普通的表达式为参数,返回该表达式的类型。他也是作为一个类型指示符,在编译时进行推导。看代码:

#include 
  
   
using namespace std;

int main(void)
{
	int i;
	decltype(i) j = 0;
	cout << typeid(j).name() << endl;

	int a;
	double b;
	decltype(a + b) c;
	cout << typeid(c).name() << endl;
	return 0;
}
  

6、继承和委托构造函数

c++中,继承类无法使用基类的非虚函数,除非显式使用。

而在c++11中,允许使用using声明来声明继承类的构造函数。如:

class A{
public:
	A() {}
	A(int i) {}
};

class B :public A{
public:
	using A::A;		//继承构造函数
	virtual void s(int i)
	{
		cout << "B:" << i << endl;
	}
};

在c++11中,标准继承构造函数被设计为跟派生类中的各种类默认函数(默认构造,析构,copy构造等)一样,都是隐式声明的。

c++11中构造函数可以调用同一个类的另一个构造函数,通过委派其他构造函数,过构造函数的类会更加容易编写:

class A{
public:
	A(int a)
	{
		this->a = a;
	}
	A() :A(0) {}
	int geta()
	{
		return a;
	}
private:
	int a;
};
int main(void)
{
	A b;
	cout << b.geta() << endl;
	return 0;
}
委派构造函数:委派函数将构造的任务委派给了目标构造函数来完成这样一种类构造的方式。

7、右值引用

在c++11中,右值是由两个概念构成的,一个是将亡值,另一个则是纯右值。

在c++11中,右值引用就是对一个右值进行引用的类型。它能够以non-const值的方式传入,允许对象去改动他。

如:T&& a = returna();

这里a是右值引用,他的值等于returna返回的临时变量的值。

8、移动语义

来看一张图:

\

看到上图,应该可以看得出上半部分是copy构造函数咯。而下面的部分就是c++11中的新特性,叫做移动构造函数。

移动移动,移为己用,他偷走了临时变量中的资源。

class string
{