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++ 语言类模板 (Class Template) -> 正文阅读

[C++知识库]C++ 语言类模板 (Class Template)

C++ 语言类模板 (Class Template)

根据“在定义变量时是否需要显式地指明数据类型”可以将编程语言分为强类型语言和弱类型语言。

1. 强类型语言

强类型语言在定义变量时需要显式地指明数据类型,并且一旦为变量指明了某种数据类型,该变量以后就不能赋予其他类型的数据了,除非经过强制类型转换或隐式类型转换。典型的强类型语言有 C/C++、Java 等。

int a = 100;
a = (int)"http://c.biancheng.net"; // 强制转换 (得到字符串的地址)

2. 弱类型语言

弱类型语言在定义变量时不需要显式地指明数据类型,编译器 (解释器) 会根据赋给变量的数据自动推导出类型,并且可以赋给变量不同类型的数据。典型的弱类型语言有 Python、Shell 等。

不管是强类型语言还是弱类型语言,在编译器 (解释器) 内部都有一个类型系统来维护变量的各种信息。

对于强类型的语言,变量的类型从始至终都是确定的、不变的,编译器在编译期间就能检测某个变量的操作是否正确,这样最终生成的程序中就不用再维护一套类型信息了,从而减少了内存的使用,加快了程序的运行。特殊情况是 C++ 中的多态。

对于弱类型的语言,变量的类型可以随时改变,赋予它什么类型的数据它就是什么类型,编译器在编译期间不好确定变量的类型,只有等到程序运行后、真的赋给变量一个值了,才能确定变量当前是什么类型,所以传统的编译对弱类型语言意义不大,因为即使编译了也有很多东西确定不下来。

弱类型语言往往是一边执行一边编译,这样可以根据上下文 (可以理解为当前的执行环境) 推导出很多有用信息,让编译更加高效。我们将这种一边执行一边编译的语言称为解释型语言,而将传统的先编译后执行的语言称为编译型语言。

强类型语言较为严谨,在编译时就能发现很多错误,适合开发大型的、系统级的、工业级的项目。弱类型语言较为灵活,编码效率高,部署容易,学习成本低。

模板所支持的类型是宽泛的,没有限制的,可以使用任意类型来替换,这种编程方式称为泛型编程。

C++ 模板也是被迫推出的,最直接的动力来源于对数据结构的封装。C++ 开发者们希望为线性表、链表、图、树等常见的数据结构都定义一个类,并把它们加入到标准库中,这样程序员直接拿来使用即可。但是这个时候遇到了一个无法解决的问题,就是数据结构中每份数据的类型无法提前预测。以链表为例,它的每个节点可以用来存储小数、整数、字符串等,也可以用来存储一名学生、教师、司机等。而 C++ 又是强类型的,数据的种类受到了严格的限制,这种矛盾是无法调和的。于是 C++ 模板技术就诞生了。

STL (Standard Template Library,标准模板库) 几乎都是使用模板来开发的。

3. 类模板

函数模板中定义的类型参数可以用在函数声明和函数定义中,类模板中定义的类型参数也可以用在类声明和类实现中。类模板的目的同样是将数据的类型参数化。

声明类模板的语法为:

template<typename 类型参数1, typename 类型参数2, …>
class 类名 {
	// 语句
};

类模板和函数模板都是以 template 开头 (也可以使用 class,它们没有任何区别),后跟类型参数。类型参数不能为空,多个类型参数用逗号隔开。

一旦声明了类模板,就可以将类型参数用于类的成员函数和成员变量了。原来使用 int、float、char 等内置类型的地方,都可以用类型参数来代替。

定义一个类来表示坐标,要求坐标的数据类型可以是整数、小数和字符串。

x = 10、y = 10
x = 12.88、y = 129.65
x = "东经180度"、y = "北纬210度"
//============================================================================
// Name        : Yongqiang Cheng
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2020 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================

template<typename T1, typename T2>
class Point {
public:
	Point(T1 x, T2 y) : m_x(x), m_y(y) { }
public:
	T1 getX() const;  // 获取 x 坐标
	void setX(T1 x);  // 设置 x 坐标
	T2 getY() const;  // 获取 y 坐标
	void setY(T2 y);  // 设置 y 坐标
private:
	T1 m_x;  // x 坐标
	T2 m_y;  // y 坐标
};

x 坐标和 y 坐标的数据类型不确定,借助类模板可以将数据类型参数化,这样就不必定义多个类了。模板头和类头是一个整体,可以换行,但是中间不能有分号。

上面的代码仅仅是类的声明,我们还需要在类外定义成员函数。在类外定义成员函数时,仍然需要带上模板头。

template<typename 类型参数1, typename 类型参数2, …>
返回值类型 类名<类型参数1, 类型参数2, ...>::函数名(形参列表) {
	// 语句
}

第一行是模板头,第二行是函数头,它们可以合并到一行,不过为了让代码格式更加清晰,一般是将它们分成两行。

template<typename T1, typename T2>
T1 Point<T1, T2>::getX() const {
	return m_x;
}

template<typename T1, typename T2>
void Point<T1, T2>::setX(T1 x) {
	m_x = x;
}

template<typename T1, typename T2>
T2 Point<T1, T2>::getY() const {
	return m_y;
}

template<typename T1, typename T2>
void Point<T1, T2>::setY(T2 y) {
	m_y = y;
}

类名 Point 后面也要带上类型参数,只是不加 typename 关键字。在类外定义成员函数时,template 后面的类型参数要和类声明时的一致。

4. 类模板创建对象

使用类模板创建对象时,需要指明具体的数据类型。

Point<int, int> p1(5, 6);
Point<int, float> p2(5, 6.6);
Point<float, char*> p3(5.5, "东经 60 度");

与函数模板不同的是,类模板在实例化时必须显式地指明数据类型,编译器不能根据给定的数据推演出数据类型。

使用对象指针的方式来实例化。

Point<float, float> *p1 = new Point<float, float>(5.5, 6.6);
Point<char*, char*> *p = new Point<char*, char*>("东经 5.5 度", "北纬 6.6 度");

需要注意的是,赋值号两边都要指明具体的数据类型,且要保持一致。

// 赋值号两边的数据类型不一致 - 错误写法
Point<float, float> *p = new Point<float, int>(5.5, 2);
// 赋值号右边没有指明数据类型 - 错误写法
Point<float, float> *p = new Point(5.5, 2);
//============================================================================
// Name        : Yongqiang Cheng
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2020 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>

using namespace std;

template<class T1, class T2>
class Point {
public:
	Point(T1 x, T2 y) : m_x(x), m_y(y) { }
public:
	T1 getX() const;  // 获取 x 坐标
	void setX(T1 x);  // 设置 x 坐标
	T2 getY() const;  // 获取 y 坐标
	void setY(T2 y);  // 设置 y 坐标
private:
	T1 m_x;  // x 坐标
	T2 m_y;  // y 坐标
};

template<class T1, class T2>
T1 Point<T1, T2>::getX() const {
	return m_x;
}

template<class T1, class T2>
void Point<T1, T2>::setX(T1 x) {
	m_x = x;
}

template<class T1, class T2>
T2 Point<T1, T2>::getY() const {
	return m_y;
}

template<class T1, class T2>
void Point<T1, T2>::setY(T2 y) {
	m_y = y;
}

int main() {
	Point<int, int> p1(5, 6);
	cout << "x = " << p1.getX() << ", y = " << p1.getY() << endl;

	Point<int, char*> p2(9, "东经 64 度");
	cout << "x = " << p2.getX() << ", y = " << p2.getY() << endl;

	Point<char*, char*> *p3 = new Point<char*, char*>("东经 64 度", "北纬 72 度");
	cout << "x = " << p3->getX() << ", y = " << p3->getY() << endl;

	return 0;
}

x = 5, y = 6
x = 9, y = 东经 64 度
x = 东经 64 度, y = 北纬 72 度
请按任意键继续. . .
//============================================================================
// Name        : Yongqiang Cheng
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2020 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <cstring>

using namespace std;

template <class T>
class CArray
{
	int size; // 数组元素的个数
	T *ptr; // 指向动态分配的数组
public:
	CArray(const int s = 0);  // s 代表数组元素的个数
	CArray(CArray &a);
	~CArray();

	void push_back(const T &v); // 用于在数组尾部添加一个元素 v
	CArray & operator=(const CArray &a); // 用于数组对象间的赋值
	T length() { return size; }
	T & operator[](int i)
	{
		// 用以支持根据下标访问数组元素,如 a[i] = 4;
		return ptr[i];
	}
};

template<class T>
CArray<T>::CArray(const int s) : size(s)
{
	if (0 == s) {
		ptr = NULL;
	}
	else {
		ptr = new T[s];
	}
}

template<class T>
CArray<T>::CArray(CArray &a)
{
	if (NULL == a.ptr) {
		ptr = NULL;
		size = 0;
		return;
	}

	ptr = new T[a.size];
	memcpy(ptr, a.ptr, sizeof(T) * a.size);
	size = a.size;
}

template <class T>
CArray<T>::~CArray()
{
	cout << "~CArray();" << endl;

	if (ptr != NULL) {
		delete[] ptr;
	}
}

template <class T>
CArray<T> & CArray<T>::operator=(const CArray &a)
{
	// 赋值号的作用是使 "=" 左边对象里存放的数组,大小和内容都和 "=" 右边的对象一样

	// 防止 a = a 这样的赋值导致出错
	if (this == &a) {
		return *this;
	}

	// 如果 a 里面的数组是空的
	if (NULL == a.ptr) {
		if (ptr != NULL) {
			delete[] ptr;
		}
		ptr = NULL;
		size = 0;

		return *this;
	}

	// 如果原有空间够大,就不用分配新的空间
	if (size < a.size) {
		if (ptr != NULL) {
			delete[] ptr;
		}
		ptr = new T[a.size];
	}

	memcpy(ptr, a.ptr, sizeof(T) * a.size);
	size = a.size;

	return *this;
}

template <class T>
void CArray<T>::push_back(const T &v)
{
	// 在数组尾部添加一个元素
	if (ptr != NULL) {
		T *tmp_ptr = new T[size + 1]; // 重新分配空间
		memcpy(tmp_ptr, ptr, sizeof(T) * size); // 拷贝原数组内容
		delete[]ptr;
		ptr = tmp_ptr;
	}
	else {
		// 数组本来是空的
		ptr = new T[1];
	}

	ptr[size++] = v; // 加入新的数组元素
}

int main()
{
	CArray<int> obj;

	for (int i = 0; i < 5; ++i) {
		obj.push_back(i);
	}

	for (int i = 0; i < obj.length(); ++i) {
		cout << obj[i] << " ";
	}
	cout << endl;

	return 0;
}
0 1 2 3 4
~CArray();
请按任意键继续. . .

References

http://c.biancheng.net/

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:03:37  更:2021-08-09 10:03:59 
 
开发: 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/10 3:07:49-

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