C++11常见语法总结

来源:互联网 发布:摄影师作品网站知乎 编辑:程序博客网 时间:2024/06/06 13:10

Override 关键字:

明确的表示一个函数是对基类中一个虚函数的重载。

class G

{

public:

 virtualvoid func(int);

};

class H: G

{

public:

 virtualvoid func(double)override; //compilation error

};

当处理到H::func()声明时,编译器会 在一个基类查找与之匹配的虚函数。

final函数和类:

C++11有两个用途,第一阻止从类继承,第二阻止一个虚函数的重载。

无子类类型:

classTaskManager

{

/*..*/

} final;

classPrioritizedTaskManager:publicTaskManager

{

};  //compilationerror: baseclassTaskManagerisfinal

禁止虚函数被进一步重载:

classA

{

pulic:

 virtual void func()const;

};

class  B:A

{

pulic:

  void func()constoverridefinal;//OK

};

classC:B

{

pulic:

 void func()const;//error, B::func is final

};

C++11之右值引用:

左值是指表达式结束后依然存在的持久对象,右值是指表达式结束时就不再存在的临时对象,一个区分左值右值的便捷方法是:看能不能对表达式取地址,如果能,就是左值,否则为右值。

 

右值一般指的是表达式中的临时变量,在C++中临时

 

变量在表达式结束后就被销毁了,之后程序就无法再引用这个变量了,C++11提供了一个方法,让我们可以引用这个临时变量,这个方法就是所谓右值引用。

那么右值引用有什么用呢?避免内存copy!因此对于赋值操作意味着内存拷贝而不是简单的赋值指针。而右值引用的一个作用就是我们可以通过重新利用临时变量(右值)来避免无意义的内存copy。

 

右值引用的符号:“&&”

int a = 0;

a是一个左值,左值是一个变量,可以被引用和多次使用。0是一个右值,不可以被引用。左值一般是非临时变量,可以被多次使用。右值只在当前表达式有效。

classMyClassB

{

public:

    void init(int & intval)

    { cout<<"use & print"<<endl;};

    void init(int &&intval)

    { cout<<"use && print"<<endl;}

};

intmain(void)

{

    int ae =10;

   MyClassB().init(10);

   MyClassB().init(ae);

    return0;

}

右值引用是用来支持转移语义,转移语义可以将资源从一个对象转移到另一个对象,这样可以减少不必要的临时对象的创建,拷贝及销毁,大幅度提高C++应用程序的性能。

浅拷贝与move语义的区别在于,浅拷贝是共享资源,而move是独占资源,浅拷贝因共享资源从而可能引发重复析构的问题,而move是独占则不会

 

标准库函数 std::move

以非常简单的方式将左值引用转换为右值引用。

https://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/

我们先定义转移构造函数。

  MyString(MyString&& str) {

    std::cout << "Move Constructoris called! source: " << str._data << std::endl;

    _len = str._len;

    _data = str._data;

    str._len = 0;

    str._data = NULL;

 }

和拷贝构造函数类似,有几点需要注意:

1. 参数(右值)的符号必须是右值引用符号,即“&&”

2. 参数(右值)不可以是常量,因为我们需要修改右值。

3. 参数(右值)的资源链接和标记必须修改。否则,右值的析构函数就会释放资源。转移到新对象的资源也就无效了。

 

 

示例程序 :

 void ProcessValue(int& i) { 
  std::cout << "LValue processed: " << i << std::endl; 
 } 
 
 void ProcessValue(int&& i) { 
  std::cout << "RValue processed: " << i << std::endl; 
 } 
 
 int main() { 
  int a = 0; 
  ProcessValue(a); 
  ProcessValue(std::move(a)); 
 }

运行结果 :

 LValue processed: 0 
 RValue processed: 0

 

精确传递(Perfect Forwarding)

Lambda表达式解析:

 

Lambda表达式是右值引用。

方便的构造匿名函数,如果代码存在大量小函数,而这些函数一般只被调用一次,不妨将他们重构成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语句,则类似 void f(...)函数。

·        省略了参数列表,类似于无参函数 f()

mutable 修饰符说明 lambda表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const方法。

exception 说明 lambda表达式是否抛出异常(noexcept),以及抛出何种异常,类似于void f() throw(X,Y)

attribute 用来声明属性。

另外,capture 指定了在可见域范围内 lambda表达式的代码内可见得外部变量的列表,具体解释如下:

·        [a,&b] a变量以值的方式呗捕获,b以引用的方式被捕获。

·        [this] 以值的方式捕获 this指针。

·        [&] 以引用的方式捕获所有的外部自动变量。

·        [=] 以值的方式捕获所有的外部自动变量。

·        [] 不捕获外部的任何变量。

此外,params 指定 lambda表达式的参数。

————————————————————————————

CharString之间的转换

C++char类型可以自动转换成string类型,即你可以用char类型字符串直接给string类型变量赋值。但反过来是不行的,string类型不能隐式的将string类型转换成char类型,想要转换,必须显式调用c_str()函数。给你举个例子:
string s1;
const char *pc = "a character array";
s1 = pc; // ok

char *str = s1; // 
编译时刻类型错误

const char *str = s1.c_str(); // ok


————————————————————

explicit构造函数的作

解析

explicit构造函数是用来防止隐式转换的。请看下面的代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

class Test1

{

public:

    Test1(int n)

    {

        num=n;

    }//普通构造函数

private:

    int num;

};

class Test2

{

public:

    explicit Test2(int n)

    {

        num=n;

    }//explicit(显式)构造函数

private:

    int num;

};

int main()

{

    Test1 t1=12;//隐式调用其构造函数,成功

    Test2 t2=12;//编译错误,不能隐式调用其构造函数

    Test2 t2(12);//显式调用成功

    return 0;

}

Test1构造函数带一个int型的参数,代码23行会隐式转换成调用Test1的这个构造函数。而Test2的构造函数被声明为explicit(显式),这表示不能通过隐式转换来调用这个构造函数,因此代码24行会出现编译错误

普通构造函数能够被隐式调用。而explicit构造函数只能被显式调用

————————————————————————

std::ifstream的使用方法和作用

ifstream 已有的文件

————————————————————————

Decltype

https://www.devbean.net/2012/05/cpp11-decltype/

decltype 类型说明符生成指定表达式的类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。

intvar;

constint&&fx();

structA { doublex; }

const A* a = new A();

 

 

语句

类型

注释

decltype(fx());

const int &&

对左值引用的const int

decltype(var);

int

变量 var 的类型

decltype(a->x);

double

成员访问的类型

decltype((a->x));

const double&

内部括号导致语句作为表达式而不是成员访问计算。由于a声明为 const指针,因此类型是对const double的引用。

 

——————————————————

 Deletedefault

 

http://blog.csdn.net/u012333003/article/details/25299939

1.   class LeafFromTree{  

2.   public:  

3.     LeafFromTree() = default;  

4.     ~LeafFromTree() = default;  

5.     

6.     LeafFromTree( const LeafFromTree& ) = delete;  // mark copy ctor or copy assignment operator as deleted functions  

7.     LeafFromTree & operator=( const LeafFromTree &) = delete;   

8.   };  

 

9.     在函数重载中,可用 delete来滤掉一些函数的形参类型,如下:

10.bool isLucky(int number);        // original function
11.bool isLucky(char) = delete;     // reject chars
12.bool isLucky(bool) = delete;     // reject bools
13.bool isLucky(double) = delete;   // reject doubles and floats

14.    这样在调用 isLucky函数时,如果参数类型不对,则会出现错误提示

15.if (isLucky('a')) …     // error !    call to deleted function
16.if (isLucky(true)) …    // error !
17.if (isLucky(3.5)) …     // error !

 

 

 C++11 中,可在想要禁止使用的函数声明后加= delete,而需要保留的加"= default"或者不采取操

 

 

 

Constexpr

 

map/unordered_map原理和使用整理

 

运行效率方面:unordered_map最高,而map效率较低但提供了稳定效率和有序的序列。

占用内存方面:map内存占用略低,unordered_map内存占用略高,而且是线性成比例的。

需要无序容器,快速查找删除,不担心略高的内存时用unordered_map;有序容器稳定查找删除效率,内存很在意时候用map。

 

 

Tuple(元组)

tuple是一个固定大小的不同类型值的集合,是泛化的std::pair。和c#中的tuple类似,但是比c#中的tuple强大得多。我们也可以把他当做一个通用的结构体来用,不需要创建结构体又获取结构体的特征,在某些情况下可以取代结构体使程序更简洁,直观。

 

创建右值的引用元组方法:forward_as_tuple。

 

std::map<int, std::string> m;

m.emplace(std::piecewise_construct,
std::forward_as_tuple(10),
std::forward_as_tuple(20, 'a'));

 

它实际上创建了一个类似于std::tuple<int&&,std::string&&>类型的tuple。