当前位置:首页 > 科技  > 软件

理解C++之类模板

来源: 责编: 时间:2023-12-18 17:37:02 333观看
导读在前面我们介绍了《C++之函数模板》今天我们继续来介绍模板的另外一种形式:类模板。与模板函数相似,类也可以被一种或多种类型参数化,标准库中的容器类就是一个具有这种特性的典型例子。类模板的声明我们通过一段例子代

在前面我们介绍了《C++之函数模板》c1s28资讯网——每日最新资讯28at.com

今天我们继续来介绍模板的另外一种形式:类模板。c1s28资讯网——每日最新资讯28at.com

与模板函数相似,类也可以被一种或多种类型参数化,标准库中的容器类就是一个具有这种特性的典型例子。c1s28资讯网——每日最新资讯28at.com

c1s28资讯网——每日最新资讯28at.com

类模板的声明

我们通过一段例子代码了解一下类模板的声明:c1s28资讯网——每日最新资讯28at.com

// 类模板声明template <typename T>class MyClass{public:    T getT();    void setT(T t);private:    T t;};// 类成员函数实现template<typename T>T MyClass<T>::getT() {    return t;}template<typename T>void MyClass<T>::setT(T t) {    this->t = t;}int main(int argc, char* argv[]) {    // 类模板使用    MyClass<int> myClass;    myClass.setT(10);    std::cout << "myClass:" << myClass.getT() << std::endl;    return 0;}

首先也是使用关键字template和关键字typename对类模板进行声明,当我们将一个类声明为类模板之后,模板参数T可以像其他任何类型一样,用于声明成员变量和成员函数。c1s28资讯网——每日最新资讯28at.com

类模板的成员函数

通过上面的实例代码,我们看到在类模板的声明内部函数时如果用到模板参数T,则不用再次使用template<typename T>,但是当实现类模板的内部函数时,如果用到了模板参数T,则还需要在函数的上方 使用template<typename T>进行标记。c1s28资讯网——每日最新资讯28at.com

也即是说为了定义类模板的成员函数,你必须指定该成员函数是一个函数模板,而且你还需要使用这个类模板的完整类型限定符。c1s28资讯网——每日最新资讯28at.com

或许你觉得每次定义类模板的内部函数都要使用到模板声明,当内部函数较多时,则会产生非常多的不必要的声明,此时我们可以直接在类的内部声明加定义同时实现:c1s28资讯网——每日最新资讯28at.com

// 类模板声明template <typename T>class MyClass{public:    // 声明加定义    T getT(){        return t;    }    // 声明加定义    void setT(T t){        this->t = t;    }private:    T t;};

在类模板中只有那些被调用的成员函数,才会产生这些函数的实例化代码。对于类模板,成员函数只有在被使用的时候才会被实例化。 显然,这样可以节省空间和时间;另一个好处是:对于那些“未能提供所有成员函数中所有操作的”类型,你也可以使用该类型来实例化类模板, 只要对那些“未能提供某些操作的”成员函数,模板内部不使用即可。c1s28资讯网——每日最新资讯28at.com

类模板的特例化

同模板函数的特化一样,你可以用模板实参来特化类模板,和函数模板的重载类似,通过特化类模板,我们可以优化基于某种特定类型的实现。c1s28资讯网——每日最新资讯28at.com

在类模板的特化过程中有两个步骤:c1s28资讯网——每日最新资讯28at.com

  • 在类的起始处声明一个template<>,接下来声明用来特化类模板的类型。这个类型被用作模板实参,且必须在类名的后面直接指定。
  • 进行类模板的特化时,每个成员函数都必须重新定义为普通函数,原来模板函数中的每个T也相应地被进行特化的类型取代。

下面是一个模板类特化的例子:c1s28资讯网——每日最新资讯28at.com

// 类模板声明template <typename T>class MyClass{public:    // 声明加定义    T getT(){        return t;    }    // 声明加定义    void setT(T t){        this->t = t;    }private:    T t;};// 类模板声明template <>class MyClass<std::string>{public:    // 声明加定义    std::string getT(){        return t;    }    // 声明加定义    void setT(std::string t){        std::cout << "调用特化类模板 setT" << std::endl;        this->t = t;    }private:    std::string t;};int main(int argc, char* argv[]) {    // 类模板使用    MyClass<std::string> myClass;    myClass.setT("hello word");    std::cout << "myClass:" << myClass.getT() << std::endl;    return 0;}

模板源码组织模式

模板源码的组织模式有好多种,这里只介绍两种常用的:分别是包含模式和关键字export的分离模式。c1s28资讯网——每日最新资讯28at.com

包含模式可以说是最常用也是最推荐的一种模式。这种模式就是将模板类的声明和定义都放在同一个文件中,这个文件一般是扩展名为.hpp的文件。c1s28资讯网——每日最新资讯28at.com

下面是一个类模板声明定义和使用分开在不同文件的例子:c1s28资讯网——每日最新资讯28at.com

MyClass.hpp#include <iostream>#include <memory>// 类模板声明template <typename T>class MyClass{public:    // 声明    T getT();    void setT(T t);private:    T t;};template<typename T>T MyClass<T>::getT() {    return t;}template<typename T>void MyClass<T>::setT(T t) {    this->t = t;}

在main函数中使用模板main.cpp:c1s28资讯网——每日最新资讯28at.com

main.cpp#include <iostream>#include <memory>#include "MyClass.hpp"int main(int argc, char* argv[]) {    // 类模板使用    MyClass<std::string> myClass;    myClass.setT("hello word");    std::cout << "myClass:" << myClass.getT() << std::endl;    return 0;}

很明显,包含模式因为包含了类模板的定义实现,因而明显增加了包含头文件.hpp的开销,这会导致大大增加了编译复杂程序所耗费的时间。 然而随着现代的机器性能提升,这里带来的编译开销基本可以忽略不计,因此这种模式成为了使用最多的模式。c1s28资讯网——每日最新资讯28at.com

下面我们再来看看关键字export的分离模式。c1s28资讯网——每日最新资讯28at.com

关键字export的功能使用是非常简单的:在一个文件里面定义模板,并在模板的定义和(非定义的)声明的前面加上关键字export。c1s28资讯网——每日最新资讯28at.com

还是以上面的代码为例:c1s28资讯网——每日最新资讯28at.com

(1) MyClass.hc1s28资讯网——每日最新资讯28at.com

#include <iostream>#include <memory>// 类模板声明export template <typename T>class MyClass{public:    // 声明    T getT();    void setT(T t);private:    T t;};

(2) MyClass.cppc1s28资讯网——每日最新资讯28at.com

#include "MyClass.h"export template<typename T>T MyClass<T>::getT() {    return t;}export template<typename T>void MyClass<T>::setT(T t) {    this->t = t;}

以上代码能否编译通过取决于你的编译器,大部分是无法编译通过的,这代码和包含模式对比起来是不是有一种脱裤子放屁的感觉?c1s28资讯网——每日最新资讯28at.com

看起来关键字export的分离模式更加符合C++源码组织习惯,为什么这种写法再C++的模板没有流行起来呢? 这是因为在C++标准推出几年之后,也就只有极少的公司真正提供了对export关键字的支持。于是,export这个特性未能像其他C++特性那样广为流传, 这就使得程序员在很多编译器下都不能正常使用export的分离模式。c1s28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-48742-0.html理解C++之类模板

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Python 的 match 有点好用,推荐试试

下一篇: Pandas的魅力:从数据处理到机器学习

标签:
  • 热门焦点
  • 一加Ace2 Pro官宣:普及16G内存 引领24G

    一加官方今天继续为本月发布的新机一加Ace2 Pro带来预热,公布了内存方面的信息。“淘汰 8GB ,12GB 起步,16GB 普及,24GB 引领,还有呢?#一加Ace2Pro#,2023 年 8 月,敬请期待。”同时
  • Mate60手机壳曝光 致敬自己的经典设计

    8月3日消息,今天下午博主数码闲聊站带来了华为Mate60的第三方手机壳图,可以让我们在真机发布之前看看这款华为全新旗舰的大致轮廓。从曝光的图片看,Mate 60背后摄像头面积依然
  • 在线图片编辑器,支持PSD解析、AI抠图等

    自从我上次分享一个人开发仿造稿定设计的图片编辑器到现在,不知不觉已过去一年时间了,期间我经历了裁员失业、面试找工作碰壁,寒冬下一直没有很好地履行计划.....这些就放在日
  • 使用AIGC工具提升安全工作效率

    在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于:开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、漏洞poc、exp
  • 共享单车的故事讲到哪了?

    来源丨海克财经与共享充电宝相差不多,共享单车已很久没有被国内热点新闻关照到了。除了一再涨价和用户直呼用不起了。近日多家媒体再发报道称,成都、天津、郑州等地多个共享单
  • 造车两年股价跌六成,小米的估值逻辑变了吗?

    如果从小米官宣造车后的首个交易日起持有小米集团的股票,那么截至2023年上半年最后一个交易日,投资者将浮亏59.16%,同区间的恒生科技指数跌幅为52.78%
  • 苹果140W USB-C充电器:采用氮化镓技术

    据10 月 30 日 9to5 Mac 消息报道,当苹果推出新的 MacBook Pro 2021 时,该公司还推出了新的 140W USB-C 充电器,附赠在 MacBook Pro 16 英寸机型的盒子里,也支
  • DRAM存储器10月价格下跌,NAND闪存本月价格与上月持平

    10月30日,据韩国媒体消息,自今年年初以来一直在上涨的 DRAM 存储器的交易价格仅在本月就下跌了近 10%,此次是全年首次降价,而NAND 闪存本月价格与上月持平。市
  • SN570 NVMe SSD固态硬盘 价格与性能兼具

    SN570 NVMe SSD固态硬盘是西部数据发布的最新一代WD Blue系列的固态硬盘,不仅闪存技术更为精进,性能也得到了进一步的跃升。WD Blue SN570 NVMe SSD的包装外
Top