前言:类模板和模板类的区别
实验六 函数模板和类模板
一.实验目的
1.理解并掌握函数模板的定义和使用方法;
2.理解并掌握类模板的定义和使用方法;
3.理解并掌握模板类的应用和实例化方法;
二. 实验内容
1. 理解并掌握函数模板的定义和使用方法
第1题:请按照下面程序主函数的调用情况,定义一个加法运算的函数模板,按照注释要求完善程序。
#include <iostream>
using namespace std;
//定义加法运算函数模板
int main()
{
int x = 12;
float y = 46.9;
//cout << add(x, y) << endl; //error,无法自动推导函数返回值
cout << add<float>(x, y) << endl; //返回值在第一个类型参数中指定
cout << add<int, int, float>(x, y) << endl;
return 0;
}
请给出完整程序的源代码,并粘贴运行结果。
#include <iostream>
using namespace std;
// 定义加法运算函数模板
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
int x = 12;
float y = 46.9;
cout << add(x, static_cast<int>(y)) << endl; // 显式指定模板参数
cout << add<float>(x, y) << endl; // 返回值在第一个类型参数中指定
return 0;
}
2.理解并掌握类模板的定义和使用方法
第2题:定义一个矩形类模板 ,模板类中的数据成员为矩形的长和宽,其成员函数实现计算矩形的周长和面积。
#include <iostream>
using namespace std;
/* 定义一个矩形类模板Rect
成员函数:calcArea()、calePerimeter()
数据成员:m_length、m_height
*/
//请完成矩形类的定义
int main(void)
{
Rect<int> rect(3, 6);
cout <<"面积为:" <<rect.calcArea() << endl;
cout << "周长为:"<<rect.calePerimeter() << endl; return 0;
}
请给出完整程序的源代码,并粘贴运行结果。
#include <iostream>
using namespace std;
// 定义一个矩形类模板Rect
template <typename T>
class Rect {
private:
T m_length;
T m_height;
public:
Rect(T length, T height) : m_length(length), m_height(height) {}
// 计算矩形的面积
T calcArea() {
return m_length * m_height;
}
// 计算矩形的周长
T calePerimeter() {
return 2 * (m_length + m_height);
}
};
int main(void) {
Rect<int> rect(3, 6);
cout <<"面积为:" <<rect.calcArea() << endl;
cout << "周长为:"<<rect.calePerimeter() << endl;
return 0;
}
3.理解并掌握模板类的应用和实例化方法
第3题:阅读下列关于数组类模板的定义和程序运行结果,按照注释要求补充类模板定义中相应的功能代码,以完成主函数对模板类数组的实例化调用。
#ifndef ARRAY_H_
#define ARRAY_H_
#include <cassert>
template <class T>
class Array {
private:
T* list;
int size;
public:
Array(int sz = 50);
Array(const Array<T>& a);
~Array();
Array<T>& operator = (const Array<T>& rhs);
T& operator[] (int i);
const T& operator[] (int i) const;
operator T* ();
operator const T* () const;
int getSize() const;
void resize(int sz);
};
template <class T>
Array<T>::Array(int sz) {
assert(sz > 0);
size = sz;
list = new T[size];
}
template <class T>
Array<T>::~Array() {
delete [] list;
}
//下面补充类模板中其它成员函数声明的实现:
#endif //ARRAY_H_
//以上为array.h头文件
#include <iostream>
#include <iomanip>
#include "array.h"
using namespace std;
void read(int *p, int n) {
for (int i = 0; i < n; i++){
cout << "请输入第" << i+1 <<"位学生的课程A成绩(0~100):";
cin >> p[i];
}
}
double calculate(int *p, int n) {
double total=0;
for (int i = 0; i < n; i++)
total += p[i];
cout << n <<"位学生的总课程为:" << total;
return total;
}
int main()
{
int n;
double average = 0;
cout << "请输入学生人数:";
cin >> n;
Array<float> score(n);
read(score, n) ;
average = calculate(score, n)/n;
cout <<n<< "位同学的平均成绩为:" << setprecision(4) << average << endl;
return 0;
}
简而言之,就是要写以下的模板:
Array<T>& operator = (const Array<T>& rhs);
T& operator[] (int i);
const T& operator[] (int i) const;
operator T* ();
operator const T* () const;
int getSize() const;
void resize(int sz);
我写的补充部分的代码:
template <class T>
Array<T>& Array<T>::operator=(const Array<T>& rhs) {
if (this == &rhs) {
return *this;
}
delete [] list;
size = rhs.size;
list = new T[size];
for (int i = 0; i < size; ++i) {
list[i] = rhs.list[i];
}
return *this;
}
template <class T>
T& Array<T>::operator[](int i) {
assert(i >= 0 && i < size);
return list[i];
}
template <class T>
const T& Array<T>::operator[](int i) const {
assert(i >= 0 && i < size);
return list[i];
}
template <class T>
Array<T>::Array(const Array<T>& a) {
size = a.size;
list = new T[size];
for (int i = 0; i < size; ++i) {
list[i] = a.list[i];
}
}
template <class T>
Array<T>::operator T* () {
return list;
}
template <class T>
Array<T>::operator const T* () const {
return list;
}
template <class T>
int Array<T>::getSize() const {
return size;
}
template <class T>
void Array<T>::resize(int sz) {
assert(sz > 0);
if (sz == size) {
return;
}
T* newList = new T[sz];
int n = (sz < size) ? sz : size;
for (int i = 0; i < n; ++i) {
newList[i] = list[i];
}
delete [] list;
list = newList;
size = sz;
}
参考答案:
template <class T>
Array<T>::Array(const Array<T>& a) {
size = a.size;
list = new T[size];
for (int i = 0; i < size; ++i) {
list[i] = a.list[i];
}
}
template <class T>
Array<T>& Array<T>::operator=(const Array<T>& rhs) {
if (&rhs != this) {
if (size != rhs.size) {
delete [] list;
size = rhs.size;
list = new T[size];
}
for (int i = 0; i < size; ++i) {
list[i] = rhs.list[i];
}
}
return *this;
}
template <class T>
T& Array<T>::operator[](int i) {
assert(i >= 0 && i < size);
return list[i];
}
template <class T>
const T& Array<T>::operator[](int i) const {
assert(i >= 0 && i < size);
return list[i];
}
template <class T>
Array<T>::operator T*() {
return list;
}
template <class T>
Array<T>::operator const T*() const {
return list;
}
template <class T>
int Array<T>::getSize() const {
return size;
}
template <class T>
void Array<T>::resize(int sz) {
assert(sz >= 0);
if (sz == size)
return;
T* newList = new T[sz];
int n = (sz < size) ? sz : size;
for (int i = 0; i < n; ++i) {
newList[i] = list[i];
}
delete[] list;
list = newList;
size = sz;
}
参考答案完整源代码:
#ifndef ARRAY_H_
#define ARRAY_H_
#include <cassert>
template <class T>
class Array {
private:
T* list;
int size;
public:
Array(int sz = 50);
Array(const Array<T>& a);
~Array();
Array<T>& operator = (const Array<T>& rhs);
T& operator[] (int i);
const T& operator[] (int i) const;
operator T* ();
operator const T* () const;
int getSize() const;
void resize(int sz);
};
template <class T>
Array<T>::Array(int sz) {
assert(sz > 0);
size = sz;
list = new T[size];
}
template <class T>
Array<T>::~Array() {
delete [] list;
}
template <class T>
Array<T>::Array(const Array<T>& a) {
size = a.size;
list = new T[size];
for (int i = 0; i < size; ++i) {
list[i] = a.list[i];
}
}
template <class T>
Array<T>& Array<T>::operator=(const Array<T>& rhs) {
if (&rhs != this) {
if (size != rhs.size) {
delete [] list;
size = rhs.size;
list = new T[size];
}
for (int i = 0; i < size; ++i) {
list[i] = rhs.list[i];
}
}
return *this;
}
template <class T>
T& Array<T>::operator[](int i) {
assert(i >= 0 && i < size);
return list[i];
}
template <class T>
const T& Array<T>::operator[](int i) const {
assert(i >= 0 && i < size);
return list[i];
}
template <class T>
Array<T>::operator T*() {
return list;
}
template <class T>
Array<T>::operator const T*() const {
return list;
}
template <class T>
int Array<T>::getSize() const {
return size;
}
template <class T>
void Array<T>::resize(int sz) {
assert(sz >= 0);
if (sz == size)
return;
T* newList = new T[sz];
int n = (sz < size) ? sz : size;
for (int i = 0; i < n; ++i) {
newList[i] = list[i];
}
delete[] list;
list = newList;
size = sz;
}
#endif // ARRAY_H_
#include <iostream>
#include <iomanip>
using namespace std;
template<typename T>
void read(Array<T>& p, int n) {
for (int i = 0; i < n; i++) {
cout << "请输入第" << i + 1 << "位学生的课程A成绩(0~100):";
cin >> p[i];
}
}
template<typename T>
double calculate(Array<T>& p, int n) {
double total = 0;
for (int i = 0; i < n; i++)
total += p[i];
cout << n << "位学生的总课程为:" << total;
return total;
}
int main() {
int n;
double average = 0;
cout << "请输入学生人数:";
cin >> n;
Array<float> score(n);
read(score, n);
average = calculate(score, n) / n;
cout << n << "位同学的平均成绩为:" << setprecision(4) << average << endl;
return 0;
}
实验七 模板的特化和偏特化
一.实验目的
1.理解并掌握函数模板全特化的定义和使用方法;
2.理解并掌握类模板特化和偏特化的定义和使用方法;
二. 实验内容
1. 理解并掌握函数模板全特化的定义和使用方法
第1题:请根据下面程序主函数的调用情况和程序运行结果,定义相应的全特化函数模板,按照注释要求完善程序,给出程序源代码及程序运行结果截图。
//template.h
#pragma once
#include <iostream>
template <typename T, typename U>
void tfunc(T& a, U& b)
{
std::cout << "tfunc 泛化版本函数" << std::endl;
}
// 补充相应的函数全特化代码
//main.cpp
#include <iostream>
#include "template.h"
using namespace std;
int main()
{
int a1 = 1;
double b1 = 3.2;
tfunc(a1, b1);
tfunc(a1, a1);
}
//template.h
#pragma once
#include <iostream>
template <typename T, typename U>
void tfunc(T& a, U& b)
{
std::cout << "tfunc 泛化版本函数" << std::endl;
}
// 补充相应的函数全特化代码
//// 函数全特化1
//template <>
//void tfunc(int& a, double& b)
//{
// std::cout << "tfunc 全特化版本函数1" << std::endl;
//}
// 函数全特化2
template <>
void tfunc(int& a, int& b)
{
std::cout << "tfunc 全特化版本函数2" << std::endl;
}
//main.cpp
#include <iostream>
#include "template.h"
using namespace std;
int main()
{
int a1 = 1;
double b1 = 3.2;
tfunc(a1, b1);
tfunc(a1, a1);
}
运行结果截图:
2. 理解并掌握类模板全特化的定义和使用方法
第2题:请根据下面程序主函数的调用情况和程序运行结果,定义一个相应的全特化函数模板,按照注释要求完善程序,给出程序源代码及程序运行结果截图。
//template.h
#pragma once
#include <iostream>
template <typename T, typename U>
class TC
{
public:
TC()
{
std::cout << "泛化版本构造函数" << std::endl;
}
void funtest()
{
std::cout << "泛化版本成员函数" << std::endl;
}
};
// 补充相应的类全特化代码
//main.cpp
#include <iostream>
#include "template.h"
using namespace std;
int main()
{
TC<char, int> tchar;
tchar.funtest();
TC<int, int> tint;
tint.funtest();
TC<double, double> tdouble;
tdouble.funtest();
}
//template.h
#pragma once
#include <iostream>
template <typename T, typename U>
class TC
{
public:
TC()
{
std::cout << "泛化版本构造函数" << std::endl;
}
void funtest()
{
std::cout << "泛化版本成员函数" << std::endl;
}
};
template <>
class TC<int, int>
{
public:
TC()
{
std::cout << "TC<int, int> 全特化版本构造函数" << std::endl;
}
void funtest()
{
std::cout << "TC<int, int> 全特化版本成员函数" << std::endl;
}
};
template <>
class TC<double, double>
{
public:
TC()
{
std::cout << "TC<double, double> 全特化版本构造函数" << std::endl;
}
void funtest()
{
std::cout << "TC<double, double> 全特化版本成员函数" << std::endl;
}
};
//main.cpp
#include <iostream>
#include "template.h"
using namespace std;
int main()
{
TC<char, int> tchar;
tchar.funtest();
TC<int, int> tint;
tint.funtest();
TC<double, double> tdouble;
tdouble.funtest();
}
程序运行结果截图:
3. 理解并掌握类模板偏特化的定义和使用方法
(1)类模板参数数量上的偏特化
第3题:请根据下面程序主函数的调用情况和程序运行结果,定义一个相应的偏特化类模板,按照注释要求完善程序,给出程序源代码及程序运行结果截图。
//template.h
#pragma once
#include <iostream>
template <typename T, typename U, typename W>
class TC2
{
public:
void funtest()
{
std::cout << "泛化版本成员函数" << std::endl;
}
};
// 补充相应的类偏特化代码
//main.cpp
#include <iostream>
#include "template.h"
using namespace std;
int main()
{
TC2<double, double, double> tdouble2;
tdouble2.funtest();
TC2<int, double, double> tint2;
tint2.funtest();
}
//template.h
#pragma once
#include <iostream>
template <typename T, typename U, typename W>
class TC2
{
public:
void funtest()
{
std::cout << "泛化版本成员函数" << std::endl;
}
};
template <typename U>
class TC2 <int, U, double>
{
public:
void funtest()
{
std::cout << "TC2 <int, U, double> 偏特化版本成员函数" << std::endl;
}
};
//main.cpp
#include <iostream>
#include "template.h"
using namespace std;
int main()
{
TC2<double, double, double> tdouble2;
tdouble2.funtest();
TC2<int, double, double> tint2;
tint2.funtest();
}
运行结果截图:
(2)类模板参数范围上的偏特化
第4题:请根据下面程序主函数的调用情况和程序运行结果,定义一个相应的偏特化类模板,按照注释要求完善程序,给出程序源代码及程序运行结果截图。
// template.h
#pragma once
#include <iostream>
template <typename T>
class TC3
{
public:
void funtest()
{
std::cout << "泛化版本成员函数" << std::endl;
}
};
// 补充相应的类偏特化代码
//main.cpp
#include <iostream>
#include "template.h"
using namespace std;
int main()
{
TC3<int> tint3;
tint3.funtest();
TC3<int&> tint3_ref;
tint3_ref.funtest();
TC3<int*> tint3_point;
tint3_point.funtest();
TC3<const int> tint3_const;
tint3_const.funtest();
}
运行结果截图:
// template.h
#pragma once
#include <iostream>
template <typename T>
class TC3
{
public:
void funtest()
{
std::cout << "泛化版本成员函数" << std::endl;
}
};
template <typename T>
class TC3<T&>
{
public:
void funtest()
{
std::cout << "T&偏特化版本成员函数" << std::endl;
}
};
template <typename T>
class TC3<T*>
{
public:
void funtest()
{
std::cout << "T*偏特化版本成员函数" << std::endl;
}
};
template <typename T>
class TC3<const T>
{
public:
void funtest()
{
std::cout << "const T偏特化版本成员函数" << std::endl;
}
};
//main.cpp
#include <iostream>
#include "template.h"
using namespace std;
int main()
{
TC3<int> tint3;
tint3.funtest();
TC3<int&> tint3_ref;
tint3_ref.funtest();
TC3<int*> tint3_point;
tint3_point.funtest();
TC3<const int> tint3_const;
tint3_const.funtest();
}
运行结果截图: