c++中的类模板

这篇具有很好参考价值的文章主要介绍了c++中的类模板。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++的类模板为生成通用的类声明提供了一种更好的方法。模板提供参数化类型,即能够将类型名作为参数传递给接收方来建立类或者函数。

一、定义类模板

#include <iostream>
#include <string>
using namespace std;
template <class T1,class T2>
class Pair
{
public:
    T1 key;  //关键字
    T2 value;  //值
    Pair(T1 k,T2 v):key(k),value(v) { };
    bool operator < (const Pair<T1,T2> & p) const;
};
template<class T1,class T2>
bool Pair<T1,T2>::operator < (const Pair<T1,T2> & p) const
//Pair的成员函数 operator <
{ //"小"的意思就是关键字小
    return key < p.key;
}
int main()
{
    Pair<string,int> student("Tom",19); //实例化出一个类 Pair<string,int>
    cout << student.key << " " << student.value;
    return 0;
}

不能将模板成员函数放在独立的实现文件中(以前,C++提供了关键字export,让您能够将模板成员函数放在独立的实现文件中,但是支持的编译器不多,C++11不再使用这样的关键字),由于模板不是函数,不能单独编译,模板必须与特定的模板实例化请求一起使用,为此,最简单的方法是将所有模板信息放在一个头文件中,并在要使用这些模板的文件中包含该头文件。

仅在程序包含模板并不能生成模板类,而必须请求实例化,为此,需要声明一个类型为模板类的对象,方法是使用所需的具体类型替换泛型名。

二、深入探讨模板类

指针栈

可以将内置类型或类对象用作类模板的类型,指针可以嘛?答案是可以,可以创建指针栈,但是如果不对程序做重大修改,将无法很好的工作,编译器可以创建类,但是使用效果就因人而异了。

数组模板示例和非类型参数

模板常用作容器类,这是因为类型参数的概念非常适合于将相同的存储方案用于不同的类型。确实,为容器类提供可重用代码是引入模板的主要动机,所以我们来看看另一个例子,深入探讨模板设计和使用的其他几个方面。具体地说,将探讨一些非类型(或表达式)参数以及如何使用数组来处理继承族。

首先介绍一个允许指定数组大小的简单数组模板。一种方法是在类中使用动态数组和构造函数参数来提供元素数目,最后一个版本的Stack模板采用的就是这种方法。另一种方法是使用模板参数来提供常规数组的大小,C++11新增的模板array就是这样做的。

#ifndef ARRAYTP_H_
#define ARRAYTP_H_
#include <iostream>
#include <cstdlib>

template<class T, int n>
class ArrayTP {
private:
    T at[n];
public:
    ArrayTP() {};

    explicit ArrayTP(const T &v);

    virtual T &operator[](int i);

    virtual T operator[](int i) const;
};

template<class T, int n>
ArrayTP<T, n>::ArrayTP(const T &v) {
    for (int i = 0; i < n; i++) {
        at[i] = v;
    }
}

template<class T, int n>
T &ArrayTP<T, n>::operator[](int i) {
    if (i < 0 || i >= n) {
        std::cerr << i << "is out of range\n" << std::endl;
        std::exit(EXIT_FAILURE);
    }
    return at[i];
}

template<class T, int n>
T ArrayTP<T, n>::operator[](int i) const {
    if (i < 0 || i >= n) {
        std::cerr << i << "is out of range\n" << std::endl;
        std::exit(EXIT_FAILURE);
    }
    return at[i];
}

#endif

关键字class(或在这种上下文中等价的关键字typename)指出T为类型参数,int 指出n的类型为int。这种参数(指定特殊的类型而不是用作泛型名)称为非类型(non-type)或表达式(expression)参数。假设有下面的声明:

ArrayTP<double, 10> arrayTp(3.14);

这将创建一个存储double类型对象,编译器使用double替换了T,使用10替换了n。

表达式参数有一些显示,表达式参数可以使整型,枚举,引用或者指针。因此double n是不合法的,但是double *pm是合法的,另外,模板代码不能修改参数的值,也不能使用参数的地址,所以在这个模板中不能使用n++或者&n这类的表达式,另外,实例化模板时,用作表达式参数的值必须是常量表达式。

表达式参数的柱要求但是每种数组大小都将生成自己的模板,也就是说,下面的声明将生成两个独立的类声明:

ArrayTP<double, 10> arrayTp1(3.14);
ArrayTP<double, 12> arrayTp2(3.14);

模板多功能性

可以将用于常规类的技术用于模板类。模板类可用作基类,也可用作组件类,还可用作其他模板的类型参数。例如,可以使用数组模板实现栈模板,也可以使用数组模板来构造数组——数组元素是基于栈模板的栈。

也可以递归的使用模板

ArrayTP<Array<int,5>,10> twodee;

与之等价的常规数组声明如下

int twodee[10][5];

默认参数

木板的另一项新特性是,可以为类型参数提供默认值。

template <class T1, class T2 = int> 
class Topo {
	...
}

三、模板的具体化

类模板与函数模板很相似,因为可以有隐式实例化、显式实例化和显式具体化,它们统称为具体化(specialization)。模板以泛型的方式描述类,而具体化是使用具体的类型生成类声明。

3.1、隐式实例化

到目前为止,本章所有的模板示例使用的都是隐式实例化(implicit instantiation),即它们声明一个或多个对象,指出所需的类型,而编译器使用通用模板提供的处方生成具体的类定义:

ArrayTP <int,100> stuff;

编译器在需要对象之前,不会生成类的隐式实例化:

ArrayTP <double,100> *tp;
tp = new ArrayTP <double,100>;

第二条语句导致编译器生成类定义,并根据该定义创建一个对象。

3.2、显式实例化

当使用关键字template 并指出所需类型来声明类时,编译器将生成类声明的显式实例化( explicit instantiation)。声明必须位于模板定义所在的名称空间中。例如,下面的声明将ArrayTP<string,100>声明为一个类;

template class ArrayTP <int,100>;

在这种情况下,虽然没有创建或提及类对象,编译器也将生成类声明(包括方法定义)。和隐式实例化一样,也将根据通用模板来生成具体化。

3.3、显式具体化

显式具体化(explicit specialization)是特定类型(用于替换模板中的泛型)的定义。有时候,可能需要在为特殊类型实例化时,对模板进行修改,使其行为不同。在这种情况下,可以创建显式具体化。

假设模板使用>运算符来对值进行比较,对于数字这管用,如果T表示一种类,则只要定义了T::operator>()方法,这也管用;但是T如果是由const char *表示的字符串,这将不管用,此时可以采用具体化方案,提供一个显示模板具体化,这将采用为具体类型定义的模板而不是为泛型定义的模板,当具体化模板和通用模板都与实例化请求匹配时,编译器将使用具体化版本。

具体化类模板定义格式

template <> class Classname<specialized-type-name> {...};

早期的编译器可能只能识别早期的格式,这种格式不支持前缀

class Classname<specialized-type-name> {...};

使用新的表示法提供一个专供const char*使用的模板,可以使用类似于下面的代码

template <> class ArrayTp<chonst char*> {
	...
};
3.4、部分具体化

C++还允许部分具体化(partial specialization),即部分限制模板的通用性。例如,部分具体化可以给类型参数之一指定具体的类型

// 通用模板
template <class T1,class T2> class Pair {...}
// 部分具体化
template <class T1> class Pair<T1,int> {...}

关键字template后面的<>声明是没有被具体化的类型参数。因此,上述第二个声明将T2具体化为int,但T1保持不变,注意,如果指定所有的类型,则<>内将为空,这将导致显式具体化。

tempplate <> class Pair<int,int> {...}

如果有多个模板可以选择,编译器将使用具体化程度最高的模板。

3.5、成员模板

模板可用作结构、类、或模板类的成员,要实现完全STL的设计,必须使用这项特性。

#ifndef ARRAYTP_H_
#define ARRAYTP_H_

#include <iostream>

using std::cout;
using std::endl;

template<typename T>
class beta {
private:
    template<typename V>
    class hold {
    private:
        V val;
    public:
        hold(V v = 0) : val(v) {}

        void show() const { cout << val << endl; }

        V value() const { return val; }
    };

    hold<T> q;
    hold<int> n;
public:
    beta(T t, int i) : q(t), n(i) {}

    template<typename U>
    U blab(U u, T t) { return (n.value() + q.value()) * u / t; }

    void show() const {
        q.show();
        n.show();
    }
};

#endif


int main() {
    beta<double> guy(3.5,3);
    guy.show();
    cout << "U was set to int" << endl;
    cout << guy.blab(10,2.3) << endl;
    cout << "U was set to double" << endl;
    cout << guy.blab(10.0,2.3) << endl;
    
    // 我们也可以显式的转化
    cout << guy.blab<int>(10.0,2.3) << endl;
}

四、将模板用作参数

您知道,模板可以包含类型参数如typename T和非类型参数 int n,模板还可以本身就是模板的参数,这种参数是模板新增的特性,用于实现STL。

template <template <typename T> class Thing>

模板参数是template < typename T > class Thing,其中template < typename T > class是类型 Thing是参数,这意味着什么呢,假设有下面的声明

Crab<King> legs;

为了使上面的声明被接受,模板参数King必须是一个模板类,其声明与模板参数Thing的声明匹配

template <typename T>
class King {...}

五、模板别名

如果能为类型指定别名,将很方便,在模板设计中尤其如此。可使用typedef 为模板具体化指定别名:

typedef std::array<double,12> arrd;
typedef std::array<int,12> arri;
typedef std::array<std::string,12> arrs;

arrd gallons;
arri days;
arrs months;

C++11新增了意向功能,使用模板提供一系列别名。

template <typename T>
using arrtype = std::array<T,12>;

这将arrtype定义为一个模板别名,可使用它来指定类型,如下所示:

arrtype<double> gallons;
arrtype<int> days;
arrtype<std::string> months;

C++11允许将语法using=用于非模板,用于非模板时这种语法与常规typedef等价文章来源地址https://www.toymoban.com/news/detail-623505.html

到了这里,关于c++中的类模板的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [开发语言][python][c++]:C++中的this指针和Python中的Self -- 26岁生日

    以朋友的新岁祝福开篇,祝笔者也祝大家☺️: 之前一直对 C++ 中的 this 和 python 中的 self 到底是什么关系,为什么 C++ 要显式的写出来,python 则不需要? 模糊不清,趁着周末整理一下相关结论,希望本篇文章可以解答这些问题,同时对C++和Python中的类加深些理解。 python 当

    2024年01月24日
    浏览(71)
  • [开发语言][c++][python]:C++与Python中的赋值、浅拷贝与深拷贝

    写在前面 :Python和C++中的赋值与深浅拷贝,由于其各自语言特性的问题,在概念和实现上稍微有点差异,本文将这C++和Python中的拷贝与赋值放到一起,希望通过对比学习两语言实现上的异同点,加深对概念的理解。 C++中所谓的 浅拷贝 就是由(系统默认的) 拷贝构造函数对

    2024年02月02日
    浏览(57)
  • 【C++】STL 算法 ① ( STL 算法相关头文件 | 函数对象 / 仿函数 简介 | 函数调用操作符 | 重写函数调用操作符的类 | 函数对象 与 普通函数区别 )

    标准模板库 STL 算法 都定义在 algorithm , numeric 和 functional 三个头文件中 ; 使用 STL 标准模板库 算法时 , 导入上述 3 个头文件 , 导入时根据需求导入即可 , 不必都导入 ; algorithm 头文件 是 3 个 STL 算法头文件中 包含算法最多的一个 , 包含常用的 : 比较算法、交换算法、查找算法

    2024年01月16日
    浏览(55)
  • 【c++】深入学习c++中的模板

        文章目录 前言 一、非类型模板参数 二、模板的特化 1.引入概念 2.模板的分离编译 总结   我们在前几篇的学习中只是使用了最简单的模板,比如用一个模板类等等,我们这篇的学习将在以前的基础上再深入的学习一下模板。   模板参数分类类型形参与非类型形参 。 类

    2023年04月09日
    浏览(33)
  • 11-3_Qt 5.9 C++开发指南_QSqlQuery的使用(QSqlQuery 是能执行任意 SQL 语句的类)

    QSqlQuery 是能执行任意 SQL 语句的类,如 SELECT、INSERT、UPDATE、DELETE 等,QSqlQuery 类的一些常用函数见表 11-11(省略函数中的 const ,省略缺省参数,不同参数的同名函数一般只给出一种参数形式)。 使用 QSqlQuery 执行不带参数的 SQL 语句时可以用 exec(QString)函数,如: 上面是

    2024年02月15日
    浏览(50)
  • 【C++11】移动赋值 | 新的类功能 | 可变参数模板

    C++11中,string中的operator= 包含 参数为右值的版本 C++98中 没有移动赋值和移动构造 , 只有参数为左值 的赋值重载(operator=)和拷贝构造 本来只有两次深拷贝,但是由于调用拷贝赋值时,内部又进行一次拷贝构造,所以导致最终进行三次深拷贝 这里编译器是不能优化的, 因为优

    2024年02月08日
    浏览(45)
  • 【高级程序设计语言C++】初识模板

    概念: 函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。 具体格式: templatetypename T1, typename T2,…,typename Tn 返回值类型 函数名(参数列表){} 输出结果: typename是用来定义模板参数,也可以使用class(切记

    2024年02月15日
    浏览(46)
  • Python小姿势 - # Python中的模板语言

    Python中的模板语言 Python是一门非常灵活的语言,其中一个体现就是它可以使用模板语言来生成静态文件。模板语言是一种特殊的语言,用来将静态文本和动态数据结合起来生成新的文本。 Python的模板语言最早出现在Web应用开发中,用来生成HTML页面。模板语言通常包含两部分

    2024年02月04日
    浏览(34)
  • 【c++】:模拟实现STL模板中的string

        文章目录 前言 一.string的模拟实现 总结   上一篇文章我们详细介绍了STL中的string的一些常用的接口,这一篇文章我们将从底层实现string类,当然我们只是实现一些重要的,经常使用的接口,并且不是完全按照STL中的string去走的。   首先我们为了防止我们写的string类与库

    2024年01月20日
    浏览(56)
  • C++中的类型查询(type trait)模板

    2023年8月10日,周四上午 C++中的类型查询(type trait)模板用于提供关于类型特征的信息, 帮助在编译期间进行类型检查和类型推导。 这些类型查询模板都定义在  type_traits  头文件中 std::is_arrayT :用于判断类型  T  是否是数组类型。 std::is_pointerT :用于判断类型  T  是否是指

    2024年02月13日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包