C++11初窥一:保证稳定性和兼容性

来源:互联网 发布:淘宝上怎么做一件代发 编辑:程序博客网 时间:2024/04/28 00:08


1.1开始支持宏_STDC_ 和 _func_

不得不吐槽,g++早就支持这俩宏了,第一个宏_STDC_还有几个衍生的宏,用来控制版本;_func_在函数定义体内使用返回函数名称,不要在形参列表中使用,原因你懂的,函数都还没声明完毕呢。

顺带提一下标准C支持的其他的宏:

     __LINE__                       在源代码中插入当前源代码行号   
     __FILE__                       在源代码中插入当前源代码文件名   
     __DATE__                       在源代码中插入当前编译日期〔注意和当前系统日期区别开来〕   
      __TIME__                       在源代码中插入当前编译时间〔注意和当前系统时间区别开来〕         
      __STDC__                       当要求程序严格遵循ANSIC标准时该标识符被赋值为1。   
      __cplusplus                    当用C++编译程序编译时,标识符__cplusplus就会被定义 


 1.2_Pragma操作符替代#Pragma宏定义

语法: _Pragma (字符常量)

好处:该操作符可以参与其他宏定义和操作符运算

实例:

#Pragma once    变为: _Pragma("once");

1.3 支持long long int

也是马后炮,一直在用了

C输出格式:long long int :%lld,unsigned long long int: %llu

1.4编译期断言:static_assert()

运行期断言函数:assert(逻辑表达式),表达式为假时调用abort()中断执行

static_assert(逻辑表达式,警告信息字符常量);

注意:逻辑表达式必须在编译期就可以断言真假!!!

请记住,static_asset 是在编译时执行的,不能用于检测运行时的值,向下面函数的参数。

void Divide(int a, int b)  {       static_assert(b==0, “Bad arguments.....leading to division by zero”);      // sorry mate! the above check is not possible via static_assert...use some other means  }  
static_assert 这个声明对于模板的调试非常有用,编译器快速执行这个常量表示式参数(不能依赖模板参数)。否则编译器当模板实例化时执行这个常量表达式的参数。

1.5 引入noexcept修饰符和noexcept操作符

从语法上讲,noexcept修饰符有两种形式,一种就是简单地在函数声明后加上noexcept关键字。比如:
void excpt_func() noexcept;

另外一种则可以接受一个常量表达式作为参数,如下所示:
void excpt_func() noexcept (常量表达式);

常量表达式的结果会被转换成一个bool类型的值。该值为true,表示函数不会抛出异常,反之,则有可能抛出异常。这里,不带常量表达式的noexcept相当于声明了noexcept(true),即不会抛出异常。

1.6支持快速初始化成员变量

#include <string>using namespace std;class Mem {public:    Mem(int i): m(i){}private:    int m;};class Group {public:    Group(){}                   // 这里就不需要初始化data、mem、name成员了    Group(int a): data(a) {}    // 这里就不需要初始化mem、name成员了    Group(Mem m) : mem(m) {}    // 这里就不需要初始化data、name成员了    Group(int a, Mem m, string n): data(a), mem(m), name(n){}private:    int data = 1;    Mem mem{0};    string name{"Group"};};// 编译选项:g++ 2-7-4.cpp -std=c++11 -c

(1)支持在类声明时初始化,其优先级低于构造函数初始化列表,因为后者要晚些发生!!

(2)初始化有两种方式:=和{}

(3)静态常量 成员 和 非常量静态成员初始化方式不变:前者里外都可以初始化,后者只能在类声明外初始化

1.7非静态成员支持sizeof()

这个变化不大,增加了对非对象的非静态成员的sizeof()支持

#include <iostream> using namespace std;   struct People {  public:      int hand;      static People * all;  };   int main() {      People p;      cout << sizeof(p.hand) << endl;         // C++98 中通过, C++11 中通过      cout << sizeof(People::all) << endl;    // C++98 中通过, C++11 中通过      cout << sizeof(People::hand) << endl;   // C++98 中错误, C++11 中通过  }  // 编译选项:g++ 2-8-1.cpp 

1.8扩展友元friend语法

看到这个,只想说,C++从此又多了一个奇巧淫技!!
(1)语法声明友元类时,可以不加class

class Poly;  typedef Poly P;   class LiLei {      friend class Poly;  // C++98通过, C++11通过  };   class Jim {      friend Poly;        // C++98失败, C++11通过  };   class HanMeiMei {      friend P;           // C++98失败, C++11通过  };  // 编译选项:g++ -std=c++11 2-9-1.cpp 
(2)可以为类模板声明友元类!!

class P;   template <typename T> class People {      friend T;  };   People<P> PP;   // 类型P在这里是People类型的友元  People<int> Pi; // 对于int类型模板参数,友元声明被忽略  // 编译选项:g++ -std=c++11 2-9-2.cpp 
对于People这个模板类,在使用类P为模板参数时,P是People<P>的一个friend类。而在使用内置类型int作为模板参数的时候,People<int>会被实例化为一个普通的没有友元定义的类型。这样一来,我们就可以在模板实例化时才确定一个模板类是否有友元,以及谁是这个模板类的友元。

1.9多态重载控制:final/override控制

(1)final拒绝重载

(2)override标识重载

struct Object{    virtual void fun() = 0;};struct Base : public Object {    void fun() final;   // 声明为final};struct Derived : public Base {    void fun();     // 无法通过编译};// 编译选项:g++ -c -std=c++11 2-10-2.cpp

struct Base {    virtual void Turing() = 0;    virtual void Dijkstra() = 0;    virtual void VNeumann(int g) = 0;    virtual void DKnuth() const;    void Print();};struct DerivedMid: public Base {    // void VNeumann(double g);    // 接口被隔离了,曾想多一个版本的VNeumann函数};struct DerivedTop : public DerivedMid {    void Turing() override;    void Dikjstra() override;           // 无法通过编译,拼写错误,并非重载    void VNeumann(double g) override;   // 无法通过编译,参数不一致,并非重载    void DKnuth() override;             // 无法通过编译,常量性不一致,并非重载    void Print() override;              // 无法通过编译,非虚函数重载};// 编译选项:g++ -c -std=c++11 2-10-3.cpp

1.10模板函数支持默认参数

模板类也是支持的。

对于多参数的模板类和模板函数来说,要求不一样!!!

模板类的默认形参书写顺序必须是从右往左,为了方便模板类具现化时类型推导

模板函数随意

template<typename T1, typename T2 = int> class DefClass1;  template<typename T1 = int, typename T2> class DefClass2;   // 无法通过编译   template<typename T, int i = 0> class DefClass3;  template<int i = 0, typename T> class DefClass4;            // 无法通过编译   template<typename T1 = int, typename T2> void DefFunc1(T1 a, T2 b);  template<int i = 0, typename T> void DefFunc2(T a);  // 编译选项:g++ -c -std=c++11 2-11-2.cpp  
函数模板的参数推导规则也并不复杂。简单地讲,如果能够从函数实参中推导出类型的话,那么默认模板参数就不会被使用,反之,默认模板参数则可能会被使用。

template <class T, class U = double> void f(T t = 0, U u = 0);   void g() {      f(1, 'c');      // f<int,char>(1,'c')      f(1);           // f<int,double>(1,0), 使用了默认模板参数double      f();            // 错误: T无法被推导出来      f<int>();       // f<int,double>(0,0), 使用了默认模板参数double      f<int,char>();  // f<int,char>(0,0)  }  // 编译选项:g++ -std=c++11 2-11-3.cpp 



0 0
原创粉丝点击