代码地址

git@github.com:CHENLitterWhite/CPPWheel.git

专栏介绍

本专栏会持续更新关于STL中的一些概念,会先带大家补充一些基本的概念,再慢慢去阅读STL源码中的需要用到的一些思想,有了一些基础之后,再手写一些STL代码。

(如果你有喜欢一些底层封装,执着于造轮子,我想这个一期不错的专栏)

函数模版

   说下自己的理解,C++通过加入参数化编程可以有效的降低软件的成本。

  •    优势

   1.通过模版机制,在需要修改代码的时候,对于相同参数的修改不需要大批量修改,降低出错概率。

   2.支持泛型编程,总的来说还是为了大量的、无意义的工作。这些工作只是因为数据类型的不同,其算法或者业务逻辑相同时,不需要键入多份代码。

  •     特征

    1.类型严格匹配是模版函数调用的先决条件

    2.函数模板不提供隐式类型转化,因此必须严格按照T --> 为了方便理解,把T看做占位符

    3.当模板函数和普通函数都符合调用规则时,优先使用普通函数,因为普通函数在编译期间就生成了函数体,而模板函数的生成需要在调用的时候。--> 这一点很重要,模版函数会进行二次编译来确定具体的类型,可以理解为替换占位符T

    4.编译器在处理函数模版的时候能够生成任意类型的函数,根据调用的时机产生不同的函数,编译器会对函数模板进行二次编译。这个参数化编程的基础,也是成为编译时多态的由来。--> 在声明的地方对模板代码本身进行编译,在调用的地方对参数化以后的具体调用进行编译。这也导致了,在使用模板函数时,需要使用hpp文件。

 demo.h

demo.cpp

main.cpp

解释下:

        我们现在知道了,模版函数会进行两次编译。在第一次编译的时候,如果将声明和定义分开,编译不通过,无法确定类型。在运行的时候才会进行类型的绑定。

        我们可以声明和定义都写在 .h中

demo.h

可以顺利编译成功,验证了我们的想法。

-------------------------------------------------------------------------------------------------------------------------

     这里引出一个问题,虽然写在.h是可以的,但是这样破坏了C++将.h和.cpp分离编程风格的原则,似乎有些不妥。

hpp文件的由来

    .h和.cpp分离之后模版第二次编译时会失败,虽然可以放到.h里面,但是这样破坏了.h和.cpp的传统。

命名空间的重要性

    当使用模版时,当模版函数相同时,在调用的时候只会使用一个模板函数。当项目比较大时,通常会通过命名空间将其隔开,这很容易理解。在项目中其实用的不多,通常情况下会以类作为空间的区分。

类模版

    类模板用于实现类所需数据的类型参数化。类模板在表示数组、表、图等数据结构时显得特别重要。这些数据结构的表示和算法不受所包含的元素类型的影响。道理跟函数模版一样,减少重复编程,降低代码错误发生的概率,降低代码冗余。

右值引用 

   [为什么需要右值引用?说白了是为了效率,对于右值引用而言,常用的场景在转义语义上,减少拷贝过程,提高程序的效率]

   左值 --> 可以出现在赋值运算符的左边,往往代表的是一个存储空间(本质上就是一个块有名字的内存块)

   右值 --> 就是我们所谓是数据,其实也不完全能这样描述。对于右值而言,他是具有存储空间的,只不过这个过程很短暂,只是用在计算过程中的,我们无法获取到,仅仅在某个表达式运行过程中存在。【通常右值是一个和运算过程相匹配的临时对象,这个临时对象在所对应的语句执行完毕之后,就销毁了。所以,我们无法从语法层面上直接访问

   

   说人话:

   左值 --> 是一个有名字的,有固定地址的对象

   右值 --> 是一个匿名的,没有固定地址的对象

程序中的体现:

int &a = x;          -->  左值引用 [左值引用替代值传递,减少拷贝]、

int &&a = x + y;  -->  右值引用[通过&&,形成的语法叫做右值引用,使得右值变成了一个与左值完全相同的持久对象]

右值引用:我们知道浅拷贝会带来资源二次释放问题,但是深拷贝在一些临时资源时又是没有必要的,这是右值引用拷贝构造函数的很大意义,即可以避免二次释放问题,又减少了数据拷贝的过程。

整个过程,看似很简单,但是对于一个追求性能和简洁的语言,是一个很大的进步。

右值引用 -- 完美转发(完美的按照我们的要求进行左值和右值转发)

这里我们需要通过move和forward函数来实现左值和右值的转化。

#include <iostream>

using namespace std;

void Func(int &x)
{
    cout << "左值" <<endl;
}


void Func(int &&x)
{
    cout << "右值" << endl;
}

void Func(const int &x)
{
    cout << "左值常" << endl;
}

void Func(const int &&x)
{
    cout << "右值常" << endl;
}

template<typename T>
void FuncT(T &&a)
{
    Func(std::forward<T> (a));
}

int main()
{

    int a = 10;

    FuncT(10);  // 右值
    FuncT(a);   // 左值
    FuncT(move(a)); // 右值
    const int b = 8;
    FuncT(b);   // 左值常
    FuncT(move(b)); // 右值常


    return 0;
}

可以看到按照我们要求进行参数匹配...这就是所谓的完美转发,笑死

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐