C++类模板(泛型编程二)

1.类模板定义

a.类模板以相同的方式处理不同的类型;
b.在类声明前使用template进行标识。

2.类模板语法规则
template <typename T>
class Operator
{
public:
	T op(T a, T b);
};

<typename T> 用于说明类中使用的泛指类型T。

a.和函数模板不同,类模板只能显示指定具体类型,无法自动推导;定义对象时要加<type>指定具体类型,如下所示。

Operator<int> op1;
Operator<string> op1;

int i = op1.op(1, 2);

string s = op2.op("Hello", "World!");

b.声明的泛指类型T可以出现在类模板的任意地方;
  
  c.类模板必须定义在.h文件中;
  
  d.且不能分开实现在不同的文件中。;
  
  e.类模板外部定义的成员函数需要加上模板<>声明。

3.类模板的应用场景

类模板主要用于存储和组织数据元素的类;类中数据组织的方式和数据元素的具体类型无关;比如:数组类、链表类、Stack类、Queue类等。
   
  C++中将模板的思想应用于类,使得类的实现不关注数据元素的具体类型,而只关注类所需要实现的功能。

4.编译器如何编译函数模板

编译器对类模板的处理方式和函数模板相同。
  
  a.编译器根据类模板的具体类型产生不同的类
  
  b.编译器会对函数模板进行两次编译,首先在声明的地方对类模板代码本身进行编译,然后在使用的地方对参数替换后的代码进行编译。

5.类模板的使用

下面给出类模板的初步使用:

Operator.h

#ifndef _OPERATOR_H_
#define _OPERATOR_H_

template < typename T >
class Operator
{
public:
    T add(T a, T b);
    T minus(T a, T b);
    T multiply(T a, T b);
    T divide(T a, T b);
};

template < typename T >
T Operator<T>::add(T a, T b)
{
    return a + b;
}

template < typename T >
T Operator<T>::minus(T a, T b)
{
    return a - b;
}

template < typename T >
T Operator<T>::multiply(T a, T b)
{
    return a * b;
}

template < typename T >
T Operator<T>::divide(T a, T b)
{
    return a / b;
}

#endif

main.cpp

#include <iostream>
#include <string>
#include "Operator.h"

using namespace std;

int main()
{
    Operator<int> op1;
    
    cout << "op1.add(1, 2) = " << op1.add(1, 2) << endl;
    cout << "op1.multiply(4, 5) = " << op1.multiply(4, 5) << endl;
    cout << "op1.minus(5, 6) = " << op1.minus(5, 6) << endl;
    cout << "op1.divide(10, 5) = " << op1.divide(10, 5) << endl;
    
    return 0;
}

运行结果如下所示:

这里写图片描述

6.多参数类模板

类模板可以定义任意多个不同的类型参数, 如下所示:

template <typename T1, typename T2>
class Test 
{
public:
	void add(T1, a, T2 b);
};

Test<int, float> t;		// 定义对象
7.类模板特化

类模板可以被特化:
  a.指定类模板的特定实现
  
  b.部分类型参数必须显示指定,比如返回值类型必须显示指定;
  
  c.根据类型参数分开实现类模板
  
  d.类模板的特化可以分为:
   部分特化:用特定规则约束类型参数;    
   完全特化:完全显示指定类型参数。

e.模板特化注意事项:
   特化只是模板的分开实现 ,本质上是同一个类模板;
   特化模板的使用方式是统一的,必须显示指定每一个类型参数。
   
下面给出模板特化的示例:

#include <iostream>
#include <string>

using namespace std;

template < typename T1, typename T2 >
class Test
{
public:
    void add(T1 a, T2 b)
    {
        cout << "void add(T1 a, T2 b) = " << a + b << endl;
        //cout << a + b << endl;
    }
};

template < typename T1, typename T2 >
class Test < T1*, T2* >      // 关于指针的特化实现
{
public:
    void add(T1* a, T2* b)
    {
        cout << "void add(T1* a, T2* b) = " << *a + *b << endl;
        //cout << *a + *b << endl;
    }
};

template < typename T >
class Test < T, T >    // 当 Test 类模板的两个类型参数完全相同时,使用这个实现
{
public:
    void add(T a, T b)
    {
        cout << "void add(T a, T b) = " << a + b << endl;
        //cout << a + b << endl;
    }
    void print()
    {
        cout << "class Test < T, T >" << endl;
    }
};

template <  >
class Test < void*, void* >    // 当 T1 == void* 并且 T2 == void* 时
{
public:
    void add(void* a, void* b)
    {
        cout << "void add(void* a, void* b)" << endl;
        cout << "Error to add void* param..." << endl;
    }
};

int main()
{  
    Test<int, float> t1;
    Test<long, long> t2;
    Test<void*, void*> t3;
    
    t1.add(1, 2.5);
    
    t2.add(5, 5);
    t2.print();
    
    t3.add(NULL, NULL);
    
    Test<int*, double*> t4;
    int a = 1;
    double b = 0.1;
    
    t4.add(&a, &b);
    
    return 0;
}

运行结果如下图所示:

这里写图片描述

8.数值型参数

模板参数可以是数值参数(非类型参数),格式如下:

template <int N>
class
{
public:
	static const int value = N;	
};

模板参数是在编译阶段被处理的单元,因此模板参数必须在编译阶段必须准确无误的唯一确定,下面列出数值型模板参数的限制:
  
  1.变量不能作为模板参数;
  2.浮点数不能作为模板参数;
  3.类对象不能作为模板参数。
  总之,一切在编译阶段无法确定的参数均不能作为模板参数。

下面是一道面试题:

用你觉得最高效的方法求1+2+3+...+N的值!

下面通过模板数值型参数给出解答:

#include <iostream>

using namespace std;

template <int N>
class Sum
{
public:
    static const int value = Sum<N-1>::value + N;
};

template < >
class Sum <1>
{
public:
    static const int value = 1;
};

int main()
{
    cout << "1+2+3+...+10 = " << Sum<10>::value << endl;
    cout << "1+2+3+...+100 = " << Sum<100>::value << endl;  
    
    
    return 0;
}

Sum::value的值在编译的时候就已经确定了,因此用此方法应该是最高效的了,下面为运行结果:

这里写图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面向对象程序设计课程作业 1. 请创建一个数据类型为T的链表类模板List,实现以下成员函数: 1) 默认构造函数List(),将该链表初始化为一个空链表(10分) 2) 拷贝构造函数List(const List& list),根据一个给定的链表构造当前链表(10分) 3) 析构函数~List(),释放链表中的所有节点(10分) 4) Push_back(T e)函数,往链表最末尾插入一个元素为e的节点(10分) 5) operator<<()友元函数,将链表的所有元素按顺序输出(10分) 6) operator=()函数,实现两个链表的赋值操作(10分) 7) operator+()函数,实现两个链表的连接,A=B+C(10分) 2. 请编写main函数,测试该类模板的正确性: 1) 用List模板定义一个List类型的模板类对象int_listB,从键盘读入m个整数,调用Push_back函数将这m个整数依次插入到该链表中;(4分) 2) 用List模板定义一个List类型的模板类对象int_listC,从键盘读入n个整数,调用Push_back函数将这n个整数依次插入到该链表中;(4分) 3) 用List模板定义一个List类型的模板类对象int_listA,调用List的成员函数实现A = B + C;(4分) 4) 用cout直接输出int_listA的所有元素(3分) 5) 用List模板定义List类型的模板类对象double_listA, double_listB, double_listC,重复上述操作。(15分) 3. 输入输出样例: 1) 输入样例 4 12 23 34 45 3 56 67 78 3 1.2 2.3 3.4 4 4.5 5.6 6.7 7.8 2) 输出样例 12 23 34 45 56 67 78 1.2 2.3 3.4 4.5 5.6 6.7 7.8

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值