zoukankan      html  css  js  c++  java
  • C++基础知识:泛型编程

    1.泛型编程的概念

    ---不考虑具体数据类型的编程模式

    Swap 泛型写法中的 T 不是一个具体的数据类型,而是泛指任意的数据类型.


    2.函数模板

    - 函数模板其实是一个具有相同行为的函数家族,可用不同类型进行调用
    - 函数模板可以根据类型实参对函数进行推导调用
    - 函数模板可以显示的指定类型参数
    - 函数模板可以被重载

    ①函数模板的语法规则
    ―template    关键字用于声明开始进行泛型编程
    ―typename  关键字用于声明泛指类型

     ②函数模板的应用
    ―自动类型推导调用
    ―具体类型显示调用

     3.函数模板的深入理解
    ― 编译器并不是把函数模板处理成能够处理任意类型的函数
    ― 编译器从函数模板通过具体类型产生不同的函数
    ― 编译器会对函数模板进行两次编译
      - 在声明的地方对模板代码本身进行编译
      - 在调用的地方对参数替换后的代码进行编译


    4.函数模板与重载

    函数模板可以像普通函数一样被重载
       C++ 编译器优先考虑普通函数
       如果函数模板可以产生一个更好的匹配 , 那么选择模板
       可以通过空模板实参列表的语法限定编译器只通过模板匹配

    注意:

    5.多参数函数模板

    函数模板可以定义任意多个不同的类型参数

    当声明的类型参数为返回值类型时 , 无法进行自动类型推导。

    不完美解决方案:
    将返回类型参数声明到第一个参数位置 , 调用时只需显示声明返回类型参数即可。

     6.类模板

    一些类主要用于存储和组织数据元素
    ―如 : 数组类 , 链表类,链表类 , Stack类,Queue类等等
    C++中可以将模板的思想应用于类中,使得类的可以不关注具体所操作的数据类型,而只关注类所需要实现的功能 :

    声明的泛指类型 T 可用于声明成员变量和成员函数
    编译器对类模板的处理方式和函数模板相同
    ― 编译器从类模板通过具体类型产生不同的类
    ― 编译器在声明的地方对类模板代码本身进行编译
    ― 编译器在使用的地方对参数替换后的代码进行编译

    由于类模板的编译机制不同 , 所以不能像普通类一样分开实现后在使用时只包含头文件,在工程实践上 , 一般会把类模板的定义直接放到头文件中!!
    只有被调用的类模板成员函数才会被编译器生成可执行代码!!!

     类模板可以被特化:用 template<>声明一个类时, 表示这是一个特化类!

     特化类模板的意义:
      当类模板在处理某种特定类型有缺陷时 , 可以通过类模板的特化来克服处理这种特定类型带来的不足

    注意:编译器优先选择特化类生成对象!!

    类模板的局部特化:可以指定类模板的特定实现 , 并要求某些类型参数仍然必须得模板的用户指定

    为什么需要特化,而不重新定义新类 ?
    ― 特化和重新定义新类看上去没有本质区别, 但是如果定义新类, 那么将变成一个类模板和一个新类,使用的时候需要考虑究竟是用类模板还是用新类
    ― 而特化可以统一的方式使用类模板和特化类 , 编译器自动优先选择特化类


    非类型模板参数的限制:
      -函数模板和类模板的模板参数可以是普通数值
      -变量不能作为模板参数
      -浮点数和类对象不能作为模板参数
      -全局指针不能作为模板参数
      -编译器的推导过程是在编译阶段完成的, 因此,编译器的推导必须依赖于特化类,否则推导过程无法结束。

    怎么判断一个变量是否为指针???(模板与可变参数函数)

    -C++中仍然支持C语言中的可变参数函数
    -C++编译器的匹配调用优先级
      重载函数
      函数模板
      可变参数函数

    工程问题:内存泄露,内存多次释放,使用越界...

    内存越界的问题常发生于数组的使用中
    ―解决方案 : 数组类
    ―工程中, 在非特殊情况下 , 要求开发者使用预先编写的数组类对象代替C 语言中的原生数组

    ②内存泄漏和内存多次释放常发生于指针的使用过程中
    ―解决方案: 智能指针
    ―工程中 , 要求开发者使用预先编写的智能指针类对象代替 C 语言中的原生指针

    工程中的智能指针是一个类模板:
      ―通过构造函数接管申请的堆内存
      ―通过析构函数确保堆内存被及时释放
      ―通过重载指针运算符* 和 - > 模拟指针的行为
      ―通过重载比较运算符 == 和 != 模拟指针的比较

    7.智能指针的深入理解:

    STL常用的7种智能指针:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、

                 boost::shared_array、boost::weak_ptr、boost:: intrusive_ptr

    ①std::auto_ptr:

    (1)    尽量不要使用“operator=”。如果使用了,请不要再使用先前对象。

    (2)    记住 release() 函数不会释放对象,仅仅归还所有权。

    (3)    std::auto_ptr 最好不要当成参数传递(读者可以自行写代码确定为什么不能)。

    (4)    由于 std::auto_ptr 的“operator=”问题,有其管理的对象不能放入 std::vector 等容器中。

    ②boost::scoped_ptr

    (1)scoped_ptr 没有 release 函数

    (2)没有重载 operator=,不会导致所有权转移,但无法赋值,拷贝智能指针。

    boost::shared_ptr
    (1)专门用于共享所有权,内部使用引用计数use_count() ,因此可以支持复制、参数传递等,也是用于管理单个堆内存对象的

    (2)同样没有release() 函数。

    boost::scoped_array

    (1)用于管理动态数组

    (2) boost::scoped_array<Simple> my_memory(new Simple[2]); // 使用内存数组来初始化

    (3)scoped_ptr 没有重载 operator*

    (4)没有重载 operator=

    ⑤boost::shared_array

    内部使用了引用计数,可以复制,通过参数来传递。

    ⑥boost::weak_ptr

    是专门为 boost::shared_ptr 而准备的,boost::weak_ptr 只对 boost::shared_ptr 进行引用,而不改变其引用计数,
    当被观察的 boost::shared_ptr 失效后,相应的 boost::weak_ptr 也相应失效

    ⑦boost::intrusive_ptr

    这是一种插入式的智能指针,内部不含有引用计数,需要程序员自己加入引用计数。

    智能指针总结:

    1、在可以使用 boost 库的场合下,拒绝使用 std::auto_ptr,因为其不仅不符合 C++ 编程思想,而且极容易出错[2]。

    2、在确定对象无需共享的情况下,使用 boost::scoped_ptr(当然动态数组使用 boost::scoped_array)。

    3、在对象需要共享的情况下,使用 boost::shared_ptr(当然动态数组使用 boost::shared_array)。

    4、在需要访问 boost::shared_ptr 对象,而又不想改变其引用计数的情况下,使用 boost::weak_ptr,一般常用于软件框架设计中。

    5、最后一点,也是要求最苛刻一点:在你的代码中,不要出现 delete 关键字(或 C 语言的 free 函数),因为可以用智能指针去管理。

  • 相关阅读:
    互联网资源获取
    Linux tomcat安装
    Linux JDK安装
    Linux入门教程
    windows命令行 查看文件树结构
    Gitea搭建及使用
    Jenkins搭建及使用
    Linux 基础环境搭建
    SpringBoot
    JSON Web Token(JWT)学习
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/6481045.html
Copyright © 2011-2022 走看看