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

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 
时间: 2024-10-11 22:55:29

C++11初窥一:保证稳定性和兼容性的相关文章

C++11初窥二: 继承构造函数和委派构造函数

分析了这两种用法,真想吐槽两句,这两个特性确实有实际需要,但客观来说,现有标准足够用,而且带来的代价也非常大,又给C++复杂的语法糖重重的抹了一笔!!! 一.继承构造函数 继承构造函数的引入原因:如果基类的构造函数很多,那么子类的构造函数想要实现同样多的构造接口,必须一一调用基类的构造函数,有点麻烦 于是乎:C++11引入继承构造函数 class _A { public: _A( int _InInt ) {;} _A( double _InDouble, int _InInt ) {;} _A

初窥c++11:lambda函数

为什么需要lambda函数 匿名函数是许多编程语言都支持的概念,有函数体,没有函数名.1958年,lisp首先采用匿名函数,匿名函数最常用的是作为回调函数的值.正因为有这样的需求,c++引入了lambda 函数,你可以在你的源码中内联一个lambda函数,这就使得创建快速的,一次性的函数变得简单了.例如,你可以把lambda函数可在参数中传递给std::sort函数 #include <algorithm> #include <cmath> void abssort(float*

初窥C++11:自动类型推导与类型获取

auto 话说C语言还处于K&R时代,也有auto a = 1;的写法.中文译过来叫自动变量,跟c++11的不同,C语言的auto a = 1;相当与 auto int a = 1;语句. 而C++11的auto是有着严格的类型推导出来的.以前是这么写 int a = 1; 现在,编译器知道a是int型了.所以可以这么写 auto a = 1; 对于类型比较长的,如vector<string>::iterator这类的,能少敲些字符了. 如果仅仅就这点作用,那么对编程实在没什么太大的益

玩转oo对象模型(1) 之 初窥c++对象模型

============================================== copyright: KIRA-lzn ============================================== 转载请注明出处,这篇是我原创,翻版必究! ============================================== 第二篇,如果写的好,请点个赞呦.当然有不对之处,非常欢迎拍砖!!!! 自我介绍: USTC研一学生,目前在intel实习,研发岗 第二篇

Java发送邮件初窥

一.背景 最近朋友的公司有用到这个功能,之前对这一块也不是很熟悉,就和他一起解决出现的异常的同时,也初窥一下使用Apache Common Email组件进行邮件发送. 二.Java发送邮件的注意事项 1.不同的邮箱有不同的支持协议,比如有些只支持SSL协议,有些只支持TLS协议,还有些同时支持SSL和TLS协议. 2.支持不同协议的邮箱,在使用Java发送邮件时要使用不同的方式发送,下面我会介绍基于SSL和TLS的两种实现方式. 附:常用邮箱的服务器(Smtp/POP3)地址和端口总结 三.代

C++拾遗(二)——初窥标准库类型

本篇博文的开始,先介绍一道书上看到的智力题:有20瓶药丸,其中19瓶装有1克/粒的药丸,余下一瓶装有1.1克/粒的药丸.有一台称重精准的天平,只是用一次天平的情况下如何找出比较重的那瓶药丸? 好了,直接公布答案.从药瓶#1取出一粒药丸,从药瓶#2取出两粒,从药瓶#3取出三粒,依此类推.如果每粒药丸均重1克,则称得总重量为210克(1 + 2 + … + 20 = 20 * 21 / 2 = 210),“多出来的”重量必定来自每粒多0.1克的药丸.药瓶的编号可由算式(weight - 210 gr

Ioc容器Autofac系列(1)-- 初窥(转)

前言 第一次接触Autofac是因为CMS系统--Orchard,后来在一个开源爬虫系统--NCrawler中也碰到过,随着深入了解,我越发觉得Ioc容器是Web开发中必不可少的利器.那么,Ioc容器是用来做什么的?用了有什么好处?我相信如果不明白这两点就很难敞开心扉接受Ioc容器. 传统解耦设计的弊端 为方便描述,举个日志的栗子.我简化实现,一个Log类,一个SaveLog方法.如果其他类想拥有记日志功能,那么只需在内部包含一个Log类型的变量: 双击代码全选 1 2 3 4 5 6 7 8

HTML5网页设计初窥系列课程

HTML5网页设计初窥系列课程(1):新Web设计标准HTML5的历史与回顾 (Level 200) HTML5网页设计初窥系列课程(2):新的页面组织标记 (Level 200) HTML5网页设计初窥系列课程(3):智能表单设计 (Level 200) HTML5网页设计初窥系列课程(4):引入多媒体对象 (Level 200) HTML5网页设计初窥系列课程(5):Canvas对象你的画布 (Level 200) HTML5网页设计初窥系列课程(6):扩展图形标记 (Level 200)

Scrapy 1.4 文档 01 初窥 Scrapy

初窥 Scrapy Scrapy 是用于抓取网站并提取结构化数据的应用程序框架,其应用非常广泛,如数据挖掘,信息处理或历史存档. 尽管 Scrapy 最初设计用于网络数据采集(web scraping),但它也可用于使用 API(如 Amazon Associates Web Services)提取数据或用作通用的网络爬虫. 爬虫(spider)示例 为了向您展示 Scrapy 带给您的是什么,我们将使用最简单的方式运行一个爬虫,向您展示一个 Scrape Spider 的例子. 这是一个爬虫的