C++11之一 语法特性的改变

本文章以<深入理解C++11>书为目录和例子,进行简要的测试如说明或者总结,后续再对特殊的,信息含量较大的特性进入深入研究。

#include <iostream>
#include <memory>
#include "tesh.h"
using namespace std;

//__func__宏,可以用在类中
struct TestStruct{
    TestStruct() : name(__func__){}
    const char* name;
};

//_Pragma操作符,用来替换#pragma预处理,这是个操作符,使用上更灵活。
//_Pragma("once")



//变长参数宏:先来看一个变长参数函数,原理是函数调用栈的数据存取
#include <stdarg.h>
void vaArgFun(int n, ...)
{
    int i, temp;
    va_list arg;
    va_start(arg, n);//va_start系列函数其实是宏定义,此处根据栈上n参数位置,就可以让arg指向后面的一系列参数。

    for(i = 0; i < n; i++)
    {
        temp = va_arg(arg, int);//根据参数类型取出参数
        cout <<" vaArg = " << temp << endl;
    }
    va_end(arg);//恢复arg
}

//那样变长参数宏,就一样道理,下面测试最好用printf系列函数,好配合参数数量的变化

#define LOG(...){\
    cout << "file = " << __FILE__;\
    cout << __VA_ARGS__ << endl; \
}

//字符串
int UnicodeTest()
{
    //分别用对应的长度和编码方式保存数据,但数据未必能够在终端显示出来
    //utf8是变长的,多字节性的,与宽字节之前需要经常转码,才能兼容
    //utf8 每个字占用的字节数量不定,所以不太适合固定偏移数组形式的取数据,代码上不太好写算法
    char utf8[] = u8"\u4F60\u597D\u554A";
    char16_t utf16[] = u"hello";
    char32_t utf32[] = U"hello is \u4F60\u597D\u554A";
    cout << utf8 <<"sizeof = " << sizeof(utf8)<< endl;
    cout << utf16 <<"sizeof = "<< sizeof(utf16) << endl;
    cout << utf32 <<"sizeof = "<< sizeof(utf32)<< endl;
    //其中还包括一些不同字节码的转换操作,同时locale支持


    //原生字符串支持
    char u8string[] = u8R"((你好啊) “” \n 123)";//R代表原生,  u8就是u8,u,U等字符宽度
    cout << u8string << endl;
}


//noexcept,指定不抛出异常,它既是修饰符,也是操作符。
//一、类的析构函数默认是noexcept(true),不抛出异常,原因如下:
//如果析构函数本身的调用就是源自于某些其它异常的抛出,那么terminate函数将被自动调用,彻底终止你的程序。  同时如果异常抛出析构函数外了
//那析构后面的代码就无法执行了。


//作为操作符,它也可以用来更通用的模板编程
template <class T>
    void fun() noexcept (noexcept(T())) {}//后面noexcept(T())是操作符,检测T()是否能够抛出异常。


//方便的就地初使化
class Init{
public:
    Init(int m):m_i(m){cout << __func__ << endl;};//也可以初使化列表方式
    ~Init(){cout << __func__ << endl;};
//private:
    int m_i = 3;//可以就地初使化
};


//非静态成员的sizeof
class People {
    public:
        int  m_p;//可以通过类引用,进行sizeof取大小,同时必须是public的,感觉用处也不大
};


//friend 友元的改进,主要由friend class A  改变成了friend A,对应模板有用,如下例子:
template <typename T> class Pep {
    friend T;//T作为了模板类的友元了,偶尔方便操作私有东西,提高性能和测试等
};

//修复符final override, 这个在JAVA里面经常见到,final就是代表对应函数不可被继续重载了,
//override就是子类说:我这是重载的,如果条件不满足,没有可重载的,就会报错了


//默认模板函数形参,与默认模板类形参
template<typename T1, typename T2 = int> class TClassTest;//从右开始才能行,因为左边可以省略
template<typename T1 = int, typename T2>  TF(T1 a, T2 b){};//比较随意,因为实参决定

//extern template,声明一个已经特例化的模板,这样手动减少代码量,
extern template void externTFun<int>(int);


//强枚举类型,C的枚举类型一是容易名字空间污染,二是,其值会强制INT的转化,造成比较的时候一些错误,
//而强制枚举就是单纯的枚举空间集合进行比较
enum class StrongEnum:char {RED,BLUE,GREEN};



//对齐测试,
int alignasTest()
{
    struct A {
        int a;
        char b;
    };
    cout << alignof(A) << endl;

    struct alignas(16) B {
        double r;
        double g;
        double b;
    };//每个占用8个,后面对齐补上,16个字节对齐,
    cout << alignof(B) << "sizeof = " << sizeof(B) << endl;
}


//继承构造函数,这个继承下来好像用处不大啊,节省一点书写?
class Dri_B : Init{
    public:
    Dri_B():Init(1){};
    ~Dri_B(){};
    //using Init:Init;
};

#include <list>
#include <vector>
//调用自身其它构造函数的方法扩展:委派构造函数
class TDConstructed
{
    template<class T> TDConstructed(T first, T last) : l(first, last){}
    list<int> l;
public:
    //就是调用其它构造函数的方式
    TDConstructed(vector<int>& v): TDConstructed(v.begin(), v.end()){}
};




//右值引用:移动语义和完美转发.  这个就是一些函数,符值上的,针对非基本类型的坑,用这些东西来填的。减少COPY

int is_rvalue_reference_test()
{
    cout << is_rvalue_reference<string &&> ::value << endl;
}


class HugeMem{
public:
    HugeMem(int size): sz(size > 0 ? size : 1) {
        c = new int[sz];
    }
    ~HugeMem() { delete [] c; }
    HugeMem(HugeMem && hm): sz(hm.sz), c(hm.c) {
        hm.c = nullptr;
    }
    int * c;
    int sz;
};


class Moveable{
public:
    Moveable():i(new int(3)), h(1024) {}
    ~Moveable() { delete i; }
    Moveable(Moveable && m)://需要一个右值引用构造函数的实现
        i(m.i), h(move(m.h)) {      // 强制转为右值,以调用移动构造函数
        m.i = nullptr;
    }
    int* i;
    HugeMem h;
};


//完美转发
void RunCode(int& a){cout << "RunCode lvalue" << endl;}
void RunCode(int&& a){cout << "RunCode rvalue" << endl;}
void RunCode(const int& a){cout << "const RunCode lvalue" << endl;}
void RunCode(const int&& a){cout << "const RunCode rvalue" << endl;}
template<typename T>
void PerfectForward(T&& t)//一、需要引用减少传参时候的临时对象创建。二、进行T类型的折叠,创造接受万能类型,传类型的引用,都完美传递。
{
    //RunCode(static_cast<const int&&>(t));//ok
    //RunCode(forward<T>(t));//传给实际调用的函数, forward 实际实现为:static_cast<T&&>
    RunCode(static_cast<T>(t));//为什么不是static_cast<T>?实际测试来看,它能够传递左值引用  常量左值引用, 右值引用,  但不能传递常量右值引用
}


//追踪返回类型,对于不知道的返回类型,或者其它时候有用。如下这些例子:
auto pf1()->auto (*)()->int(*)(){
    return nullptr;
}
template<class T>
auto Forward(T t)->decltype(t){//推导返回类型
    return t;
}


//for语句改变,这些来自其它语言,以及for_each也类似之前模板
#include <algorithm>
int action1(int& e){e *= 2;}
void fortest()
{
    int arr[19] = {1,3,4,9};
    vector<int> v{10,3,1,2,1};
    for_each(v.begin(), v.end(), action1);
    for(auto& e:arr)
        cout<<e<<endl;
}

//constexpr常量表达式,修饰下函数和值等,这样编译阶段就可以优化一下,少一些数据占用


//变长模板,包括变长模板类和模板函数,主要采用递归的方式进行定义和理解
//核心概念是定义时候的:参数包,   和 模板内部使用时候的: 包扩展

template<typename... E> class my_tuple;//声明其形式
template<typename H, typename... Tail>//...x代表参数包
class my_tuple<H, Tail...> : private my_tuple<Tail...>{};//x...代表包扩展,这里实现递归的主体关系
template<>class my_tuple<>{};//递归的边界条件,是参数取到数量为0个。

//模板函数的变长,理解方式一样,定义的时候也是主要找出其递归逻辑

//另外一种包扩展就是类似把B<A...>写成外部的B<A>...  这些展开方式是不一样的,不过相信可以理解


//原子类型等atomic_int,还有其它关于指令执行顺序的保证,还有线程相关等,属于基本概念,不做说明


//默认函数的控制,"=default" "=deleted",主要是针对那些默认生成的类函数,比如构造,析构等,进行删除和使用默认
//删除是不想别人使用它,比如COPY构造,    使用默认比如是因为规则上,那些默认生成的,可能你自定义了一个
//那剩下的那些可能都不会自动生成了,但有时候,你为了什么POD规则,保持纯性,还是使用默认的


//lambda函数,这里只给出一些基本的说明,后面函数式编程和模板编程上,再进入深入研究
//[capture](parameters) mutable->return-type

int lambda_test()
{
    int a = 10, b = 11;
    auto add = [=](int c)->int {return a + b + c;};//[=]捕捉列表的一种,捕捉父作用域内的变量值或者引用,或者this,后面分别是参数,返回值 ,函数体等
    return add(9);
}
int main()
{
    TestStruct test;
    cout << "__func__ = " << test.name << endl;

    //
    vaArgFun(4, 1, 2, 3, 5);

    LOG("log test");
    //
    UnicodeTest();

    //编译器支持c++的版本
     cout << "c++ version is " <<__cplusplus << endl;


     //静态断言,这个需要编译时期可以确定的常量,可判定,  用处一般般.
     //static_assert(sizeof(char) == sizeof(long), "type len is not equal !");

     cout << sizeof(People::m_p) << endl;
     cout << (StrongEnum::RED < StrongEnum::GREEN) <<endl;

     //智能指针,跟平时自己封装的概念差不多
     unique_ptr<Init> uPtr(new Init(4));
     shared_ptr<Init> sPtr = make_shared<Init>(5);
     weak_ptr<Init> wPtr = sPtr;
     sPtr.reset();//显示释放
     cout << wPtr.lock() << endl;//得到对象强指针

     alignasTest();

     is_rvalue_reference_test();

     //
     int lvalue = 33;
     const int clvalue = 33;
     PerfectForward(lvalue);
     PerfectForward(clvalue);
     PerfectForward(33);
     PerfectForward(move(lvalue));
     PerfectForward(move(clvalue));
     RunCode(move(clvalue));

     fortest();
     return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值