C++模版简单认识与使用

目录

前言:

1.泛型编程

2.函数模版

3.类模版

为什么要有类模版?使用typedef不行吗?

类模版只能显示实例化:

注意类名与类型的区别:

注意类模版最好不要声明和定义分离:

总结:


前言:

正如标题而言,这里只是对模版的简单认识与使用,方便后面博客介绍stl中一些容器的实现,更复杂详细的模版相关的内容将会在模版进阶中介绍。

1.泛型编程

编写与类型无关的通用代码,是代码复用的一种手段,模版是泛型编程的基础。

而模版又分为函数模版与类模版。

2.函数模版

template<class T>
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}


int main()
{
	int a = 1, b = 2;
	double c = 1.0, d = 2.0;
	
	Swap(a, b);
	Swap(c, d);

	return 0;
}

首先要注意第一点:

两次调用的Swap函数实际都不是同一个函数,第一是函数调用开辟的栈帧都不一样大,一个是int,一个是double;第二是汇编call的函数的地址也是不一样的。

这里的class可用typename替换,区别在后面的学习中会介绍。

 

补充一下库中的swap函数:

 

那模版参数是怎么识别不同的类型的呢?这就是模版的实例化,实际就是编译器帮你完成了这个工作,是隐式的实例化自动推演模版的类型。模版的实例化发生在编译时期,所以是在编译的时候根据类型推导生成的代码

那下面来看两个问题,首先第一个,传的模版参数不明确,会报错:

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}


int main()
{
	int a = 1;
	double b = 1.1;
	Add(a, b);//报错

解决方法1:

强制转换类型,但是会丢失精度。

Add(a1,(int)d1);

 解决方法2:

使用显示实例化,其实经历了隐式类型转换:

cout<<Add<int>(a,b)<<endl;//实际b转int经过了隐式类型转换

问题2,这样的能同时存在吗:

int Add(int left, int right)
{
	return left + right;
}

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}

template<class T1,class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}


int main()
{
	int a = 1;
	double b = 1.1;
	Add(a, b);
}

首先,前两个能同时存在吗?答案是可以的,因为函数名的修饰规则可能不一样。

其次,调用的时候都传的类型是int类型,前两个应该谁先调用呢?答案是会调用第一个,因为第一个在编译是就确定了地址,直接就调用了,而第二个在编译时才根据类型推导生成对应的代码,也就是先要经历模版的实例化。

那如何就想调用模版呢?使用模版的显示实例化呗,Add<int>(a,b);

那在这3个模版中,传的类型不一样,会先去调用哪一个?答案是去调用第三个,编译器是聪明的,会去调用最合适最匹配的那一个;而如果没有第三个,对应的才会调用第二个。

 

3.类模版

格式就是:

template<class T1,class T2,...,class Tn>
class 类模版名
{
   //类成员定义
};

 

为什么要有类模版?使用typedef不行吗?

如果我们使用typedef,那第一类想要int,第二个类想要double,是不是还要再写两个类?所以就用到了类模版,但是还是调用了两个类,编译器帮你实现了:

注意类里面的构造函数new了,需要析构时delete,因为类的对象销毁会调用析构。

类模版只能显示实例化:

因为就算调用构造函数也传不到T的身上啊,并且传的值要怎么识别是T呢?

注意类名与类型的区别:
	vector<int> v1;

不加上模版参数只是类名,加上才是类型。

注意类模版最好不要声明和定义分离:

(这里指的是头文件放类模版的定义,.cpp文件放声明,分文件的声明定义分离),否则会出现链接错误(虽然有解决方式,但是还是不建议,至于为什么到模版进阶会介绍)。

如果想要类模版的声明和定义分离,目前可以放到在同一个文件里面,然后可以在类里面声明,在类外面定义(拿析构函数举例),注意类模版的定义要写在这个类的下面,不然找不到。但是还是不建议分开写,容易出错:

class Vector
{
public:
	Vector(int capacity=4)
	{
		_pDate = new T[capacity];
		_size = _capacity = 0;
	}
	~Vector();

private:
	T* _pDate;
	int _size;
	int _capacity;
};

template<class T>
Vector<T>::~Vector()
{
	delete[] _pDate;
	_pDate = nullptr;
	_size = _capacity = 0;
}


int main()
{
	Vector<int> v1;
	return 0;
}

 

总结:

本篇偏重基本的使用和注意事项,关于模版更进阶的到模版进阶篇再介绍。

相关推荐

  1. C++ 如何去认识模板

    2024-04-07 12:12:07       17 阅读
  2. C#Tcp简单使用

    2024-04-07 12:12:07       14 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-07 12:12:07       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-07 12:12:07       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-07 12:12:07       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-07 12:12:07       20 阅读

热门阅读

  1. 4.6

    2024-04-07 12:12:07       14 阅读
  2. JVM常量池

    2024-04-07 12:12:07       18 阅读
  3. MySQL中的事务隔离级别与MVCC及两者间的关联

    2024-04-07 12:12:07       15 阅读
  4. Netty和websocket,如何部署Netty

    2024-04-07 12:12:07       13 阅读
  5. 用FPGA搞图像算法需要具备哪些基础

    2024-04-07 12:12:07       12 阅读
  6. 手写一个民用Tomcat (02)

    2024-04-07 12:12:07       15 阅读
  7. 计算机网络的分层结构及模型

    2024-04-07 12:12:07       16 阅读