IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 中的 模板类 简介 -> 正文阅读

[C++知识库]C++ 中的 模板类 简介


前言

这一章主要讲类模板,包括它的主要用法和作用,简单写了一下和普通类的异同。
本文主要为学习心得笔记,如有纰漏,欢迎指正


一、类模板简介

与模板函数相同,若想要将类中的某个数据类型抽象化,在使用是再指定需要的数据类型,就需要使用模板类来实现。

定义:

template<class T>		//class 可以用typename替换
class 类名
{
	//...
};

与函数模板的区别

  1. 类模板一般情况下无法自动类型推导的调用方式
  2. 类模板在模板参数列表可以有默认参数,写法:
template<class T = 数据类型>
  1. 类模板在有默认参数类型时,可以发生隐式类型转化
    例:

//有默认参数类型的类模板
template<class NameT, class IdT = int>
class Person1
{
	NameT name;
	IdT id;
public:
	Person1(NameT name, IdT id)
	{
		this->name = name;
		this->id = id;
	}
	void myPrint()
	{
		cout << name << endl;
		cout << id << endl;
	}
};

void test1()
{
	//错误用法,没有传入参数类型
	//Person1<> p("gzy", 10);	
	//Person1 p("gzy", 10);	
	
	//调用有默认参数类型的类模板
	Person1<string> p("gzy", 'a');	//会发生隐式类型转化
	Person1<string, char> p1("gzy", 'a');
	p.myPrint();
}

类模板内函数的创建时机

  • 普通类内的成员函数在编译时就会创建,类模板中的成员函数在调用时才会被创建,也就是说在主动调用前,编译器都看不到类模板的成员函数的内容。
  • 类模板中的成员函数,里面写的东西只要语法正确,就会被编译通过,不会进行数据类型的判断
  • 例:比如你类内函数的功能是对值类型数据进行数学运算,但是你传入一个数组类型,这时只要你不主动调用该函数,该函数将不会被编译器识别并报错。

二、类模板的各种应用

1.类模板对象做函数参数

  • 共三种传参方式:
  1. 指定类型传入
    将所有模板类用到的泛型逐个写入参数列表
void printPerson1(Person<string, int> &p){}
  1. 参数模板化
    将函数模板化,参数列表用泛型表示即可
template<class T1, class T2>
void printPerson2(Person<T1, T2> &p){}
  1. 整个类模板化
    将整个类抽象成一个模板
template<class T>
void printPerson3(T & p){}

2.类模板的继承

如果父类是一个类模板,则子类在继承时必须指定父类T的类型

  1. 第一种方法,继承时指定类型
	template<class T> 
	class Base 
	{ 
		T m; 
	};

	//可以直接尖括号跟后面
	class Son : public Base <int> {}
  1. 第二种方法,将子类也变为模板,这样可以灵活指定父类类型
	template<class T> 
	class Base 
	{ 
		T m; 
	};
	
	template<class T>
	class Son : public Base<T> {}

3.类模板中成员函数类外实现

  1. 构造函数的类外实现:
    相比普通构造函数类外实现,需要加上template和参数列表,作用域之后需要加上参数列表中的参数,这样才能识别是该类的函数。
template<class NameT, class IdT>
class Person
{
	NameT name;
	IdT id;
public:
	Person(NameT name, IdT id);
};

//构造函数类外实现:
template<class T1, class T2>
Person<T1, T2>::Person(){}
  • 成员函数的类外实现
    道理都差不多,也是必须加上template和参数列表,作用域后跟参数列表
template<class T1, class T2>
void Person<T1, T2>::func(){}

4.类模板的分文件编写

  • 问题:类模板中的成员函数创建时机是在调用阶段,导致分文件: 编写时链接不到。
  • 分文件:分为(.h)(.cpp)两个文件,分别存放声明和实现
  • 由于函数在调用时才会被创建,所以分文件操作后,运行会导致找不到函数的实现,即找不到cpp文件中的内容。
  1. 解决方法1:
    直接包含.cpp源文件,include时将"xxxx.h"改为"xxxx.cpp"即可
  2. 解决方法2:
    将声明和实现写在同一个文件,后缀名改为.hpp (hpp是约定名称,并非强制),调用同样调用"xxxx.hpp"

注:后面案例会写

  • 类模板的友元函数:
    最好在类内实现,类外实现比较繁琐,不建议写类外实现

注:类内成员函数加上friend关键字后就会变为全局函数


三、模拟实现模板类

注:这里写的功能比较杂,只作为参考,练习使用。

  • 以下内容均包含在 “myVector.hpp” 文件中
#pragma once
#include <iostream>
#include <string>
using namespace std;

template<class T>
class myVector
{
	T* arr;
	int capacity = 4;
	int count;
public:
	/*四个构造函数*/
	myVector();
	myVector(int capacity);
	myVector(int capacity, T ele);
	myVector(const myVector& p);

	/*析构函数*/
	~myVector();

	/*重载运算符*/
	myVector& operator= (const myVector& p);

	/*尾插*/
	void push_back(const T& val);

	/*尾删*/
	void pop_back();

	/*重载[]*/
	T& operator[] (int index);

	/*打印*/
	void print();
};

template<class T>
myVector<T>::myVector()
{
	capacity = 4;
	arr = new T[4];
	count = 0;
}

template<class T>
myVector<T>::myVector(int capacity)
{
	this->capacity = 4;
	while (this->capacity < capacity)
	{
		this->capacity <<= 1;
	}
	arr = new T[this->capacity];
	count = capacity;
}

template<class T>
myVector<T>::myVector(int capacity, T ele)
{
	while (this->capacity < capacity)
	{
		this->capacity <<= 1;
	}
	arr = new T[this->capacity];
	count = capacity;
	for (int i = 0; i < count; i++)
	{
		arr[i] = ele;
	}
}

template<class T>
myVector<T>::myVector(const myVector& p)
{
	*this = p;	//调用重载的 = 运算符
}

template<class T>
myVector<T>::~myVector() 
{
	if (arr != nullptr)
	{
		delete[] arr;
		arr = nullptr;
	}
	capacity = 0;
	count = 0;
}

template<class T>
myVector<T>& myVector<T>::operator= (const myVector& p)
{
	myVector<T>::~myVector();	//可以手动调用析构函数
	count = p.count;
	capacity = p.capacity;
	arr = new T[capacity];
	copy(p.arr, p.arr + count, arr);
	return *this;
}

template<class T>
void myVector<T>::push_back(const T& val)
{
	if (capacity <= count)	//扩容
	{
		capacity <<= 1;
		T* newArr = new T[capacity];
		copy(arr, arr + count, newArr);
		delete arr;
		arr = newArr;
	}
	arr[count] = val;
	count++;
}

template<class T>
void myVector<T>::pop_back()
{
	count -= (count > 0 ? 1 : 0);
}

template<class T>
T& myVector<T>::operator[] (int index)
{
	return arr[index];		// 使用[]来改变数值
}


template<class T>
void myVector<T>::print()
{
	for (int i = 0; i < count; i++)
	{
		cout << arr[i] << endl;
	}
}

总结

这一章主要记录模板类的学习,模板类的使用注意事项。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 10:54:41  更:2022-09-13 10:58:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 16:19:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码