【十七】类模板(上)

1、引入类模板

C++中可以将模板的思想应用于类,使得类可以不关注具体操作的数据类型,而只关注类所需要实现的功能。

C++中的类模板

  • 提供一种特殊的类以相同的行为处理不同的类型
  • 在类声明前使用template进行标识
  • < typename T> 用于说明类中使用的泛指类型 T
  • 在模板类外部定义成员函数的实现时,需要加上template < typename T>的声明,并且类作用域为:classname< T >::

示例:

#include <iostream>

using namespace std;

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

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

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


int main()
{
  Test<int> ti;

  cout << ti.add(4,5) << endl;
  cout << ti.minus(4,5) << endl;

  Test<double> td;

  cout << td.add(3.14,5.0) << endl;
  cout << td.minus(3.14,5.0) << endl;

  return 0;
}

Tip:

  • 声明的泛指类型 T 可用于声明成员变量和成员函数
  • 编译器对类模板的处理方式和函数模板相同
    • 编译器从类模板通过具体类型产生不同的类
    • 编译器在声明的地方对类模板代码本身进行编译,这个编译只是进行语法等检查,并不生成实际的汇编代码,因为类所处理的具体类型都还未知
    • 编译器在使用的地方对参数替换后的代码进行编译,该编译会生成具体的汇编代码

 
 
2、类模板的应用

如上面的示例,主函数如下:

int main()
{
  Test<int> ti;   //必须使用具体类型定义对象

  cout << ti.add(4,5) << endl;
  cout << ti.minus(4,5) << endl;

  Test<double> td;    //必须使用具体类型定义对象

  cout << td.add(3.14,5.0) << endl;
  cout << td.minus(3.14,5.0) << endl;

  return 0;
}

Tip:
  对于模板类来说,定义对象时必须指定明确的类型,它不能进行类型推导!

 
 
3、类模板的工程应用

  一般工程中,我们常把源文件分为.h头文件和.cpp实现文件,但在模板类中,这一方法却边得不可行!

示例:
将上述程序分离,拆分成main.cpp test.h test.cpp文件:

test.h

#ifndef _TEST_H_
#define _TEST_H_

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

#endif

test.cpp

#include "test.h"

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

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

main.cpp

#include <iostream>
#include "test.h"
using namespace std;


int main()
{
  Test<int> ti;   //必须使用具体类型定义对象

  cout << ti.add(4,5) << endl;
  cout << ti.minus(4,5) << endl;

  Test<double> td;    //必须使用具体类型定义对象

  cout << td.add(3.14,5.0) << endl;
  cout << td.minus(3.14,5.0) << endl;

  return 0;
}

使用如下命令编译:

g++ -Wall -g main.cpp test.cpp -o main

编译器提示错误:

这里写图片描述

Tip:
  出现这种错误的原因是,由于类模板的编译机制不同,所以不能像普通类一样分开实现后,在使用时只包含头文件!

现在,做一些改动,把main.cpp文件中包含的test.h头文件直接换成test.cpp,然后再次编译;会发现编译通过了!但是这样做又确实不好,该如何是好?

  • 一种方法:直接把声明和定义都放在头文件中;这种做法可行,但不利于声明和定义分离!
  • 另一种方法:把声明放在头文件中,把定义放在.hpp文件中,使用时直接包含.hpp文件,换一个方式实现声明和定义分离!

示例:

test.h 不改变,main.cpp 中直接包含test.hpp即可!
test.hpp

#ifndef _TEST_DEF_H_        //防止重复包含
#define _TEST_DEF_H_

#include "test.h"

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

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

#endif

Tip:
  只有被调用的类模板成员函数才被编译器生成可执行代码!!!

 
 
4、类模板的特化

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

示例:

这里写图片描述

特化类模板的意义

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

注意:

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

示例:

#include <iostream>
using namespace std;

template <typename T>
class Test
{
public:
  T test(T t)
  {
    cout << "T test(T t)" << endl;
    return t * t;
  }
};

//该类相当于我们手动生成的上面模板类的一个特例
template <>
class Test<int>
{
public:
  int test(int t)
  {
    cout << "int test(int t)" << endl;
    return t * t;
  }
};


int main()
{
  Test<int> ti;   //必须使用具体类型定义对象,优先匹配特化类

  cout << ti.test(4) << endl;

  Test<double> td;    //必须使用具体类型定义对象

  cout << td.test(3.14) << endl;

  return 0;
}

另外,上面的class Test< int >类其实也是一个模板类,只不过我们让它成为了一个特例,其实我们可以通过继承,让它变成普通类!

#include <iostream>
using namespace std;

template <typename T>
class Test
{
public:
  T test(T t)
  {
    cout << "T test(T t)" << endl;
    return t * t;
  }
};

//该类相当于我们手动生成的上面模板类的一个特例
template <>
class Test<int>
{
public:
  int test(int t)
  {
    cout << "int test(int t)" << endl;
    return t * t;
  }
};

//继承自特化类
class myTest : public Test<int>
{

};

int main()
{
  Test<int> ti;   //必须使用具体类型定义对象,优先匹配特化类

  cout << ti.test(4) << endl;


  myTest mt;      //直接实例化,并调用成员函数
  cout << mt.test(4) << endl;

  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值