函数模板与类模板

1、函数模板:所谓函数模板,就是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表,凡是函数体相同的函数都可以用这个模板来代替。

函数模板的出现将算法与数据类型相分离,专注于算法的设计。   

1)函数模板的定义是通过关键字 template 来实现的。如:

template <typename T>	 // 注意末尾没有分号
void test(T a){}
2)调用方式:
 test<float>(a, b);      // 显示类型调用
 test(a, b);             // 隐式类型推导 
3)函数模板的重载:

普通函数支持的隐式转换模板的数据类型并不支持,必须指明类型;

当普通函数和函数模板都可以被调用时,C++编译器会优先选择普通函数;但此时若模板更优时,还是会选模板的(比如普通函数需要隐式转换时)。

先要强制调用模板的话,可以指定类型(当然,空类型就够了);

4)生成规则:在函数模板声明时,会编译模板本身;而在调用时,会根据传入类型来生成具体函数;

2、类模板:类模板的出现主要是为了实现所需数据的类型参数化。类模板的定义方式和用法都类似函数模板。但在类模板被用来定义对象时,必须指明类型。

Test<int> a;
Test<int> b(3);

1)当模板类对象作函数参数传递时,可以有以下2种方式:

1、指明类型 2、所用函数也写成函数模板

2)类模板的派生类:

1、派生具体类,需要写清楚基类的类型

class B : public A<int>
{
public:
  B(int a, int b) : A<int>(a)
  {
     this->b = b;
  }
protected:
  int b;
};

2、派生模板类

template <typename T>
class C : public A<T>
{
public:
  C(T c, T a) : A<T>(a)
  {
    this->c = c;
  }
protected:
 T c;
};
3)类的实现在类的内部

模板类的友元函数要在类的内部实现(但它还是友元,不能去掉friend);当然,不用再定义为模板函数了。比如这样一个 << 操作符的重载函数:

template <typename T>
class Complex
{
	friend ostream &operator<< (ostream &out, Complex<T> &obj)
	{
		out << obj.a << " + " << obj.b << "i";
		return out;
	}
private:
	T a;
	T b;
};
4)类的实现在类的外部

当类的实现是在类的外部时,所有函数都要定义成模板函数。在函数实现时还要加上域解析符,如:

template <typename T>
Test<T>::Test (){}

当友元函数想要在外部实现时,过程十分复杂:

1、进行模板类声明

2、声明友元函数(模板类)

3、在类的内部进行友元函数的声明(友元,非模板),此时需要在函数名后面加上参数类型 <T>,如

friend Complex<T> mySub <T>(Complex<T> &c1, Complex<T> &c2);

4、在类的外部实现(在友元函数内部定义对象时要指定<T>,返回值也需要加上)

5)模板类的声明和实现在不同的文件中时:

在main 函数中需要包含模板类的实现文件;通常这种需要被包含的实现文件,后缀一般要写成.hpp

6)模板类中的static:模板类中的静态成员变量也需要在类的外部初始化

T A<T>::a = 0;
类模板生成的每一个模板类都有自己的静态变量,不同的模板类的静态变量是不共享的;

7)数组的类模板

当自定义类型存放在数组中时,自定义类中需要加上无参构造;

由于数组打印是通过重载左移操作符来实现的,所以需要在自定义类中也要实现左移操作符的重载;

数组内部所做的是值拷贝,默认的赋值方式是浅拷贝,一旦涉及指针的操作就会导致问题,所以需要做赋值操作符= 的运算符重载

另外,在做delete操作时,无参构造中指针需要指向NULL;

3、一定要注意 delete 数组时,要加上[ ] ,真的是很难找啊!!!!!


附上一个数组类模板的头文件:

#ifndef __MYARRAY_H__
#define __MYARRAY_H__
#include <iostream>

using namespace std;

template <typename T>
class MyArray
{
	friend ostream& operator<< <T>(ostream & out,MyArray<T> &obj);
public:
	MyArray(int len);
	MyArray(const MyArray &obj);
	~MyArray();
	int Getlen();
	T & operator[](int index);
	MyArray& operator= (const MyArray &obj);
private:
	int len;
	T *m_p;
};

template <typename T>
MyArray<T>::MyArray(int len)
{
	this->len = len;
	m_p = new T[len];
	//m_p = NULL;
}

template <typename T>
MyArray<T>::MyArray(const MyArray &obj)
{
	//len = obj.Getlen();		// Getlen 存在this指针转换
	len = obj.len;
	m_p = new T[len];

	for (int i = 0; i < len; i++)
	{
		m_p[i] = obj.m_p[i];
	}
}

template <typename T>
MyArray<T>::~MyArray()
{
	if (m_p != NULL)
	{
		delete [] m_p;		// !!!!!!!!!!!!!!!!!
		m_p = NULL;
	}
	len = 0;
}

template <typename T>
int MyArray<T>::Getlen()
{
	return len;
}

template <typename T>
T & MyArray<T>::operator[](int index)
{
	return m_p[index];
}

template <typename T>
MyArray<T>& MyArray<T>::operator=(const MyArray &obj)
{
	// 1
	if (this == &obj)
	{
		return *this;
	}
	// 2
	if (m_p != NULL)
	{
		delete [] m_p;
	}
	// 3
	m_p = new T[obj.len];
	// 4
	len = obj.len;
	for (int i = 0; i < len; i++)
	{
		m_p[i] = obj.m_p[i];
	}

	return *this;

}

template <typename T>
ostream& operator<<(ostream & out,MyArray<T> &obj)
{
	for (int i = 0; i < obj.len; i++)
	{
		//out << obj.m_p[i];
		out << obj.m_p[i] << " ";
	}
	out << endl;

	return out ;
}


#endif //__MYARRAY_H__



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值