c++ 的模板类声明基本用法

#include <iostream>
using namespace std;
template<typename T> // template 是声明模板 <typename T> 是类型 也可以写成<class T> 都是一样的
class Vector {
public: // 普通类的构造函数都是 类名() 但是模板类就必须Vector<type>()了
	explicit Vector<T>(int cap = 5); // 体类定义就跟普通的构造函数一样 但是还是要Vector<type>()开始 因为T才是完整型
	~Vector<T>() { delete[] date; }; //{ delete[]date; } // 体类声明QWQ

	T& operator[](size_t index);
	const T& operator[](size_t index)const;
	Vector<T>(const Vector<T>& array);
	Vector<T>& operator=(const Vector<T>& rhs);
	bool push_back(const T &e);
	size_t size()const { return n; }
private:
	T* date{ nullptr };
	size_t capacity{ 0 };	//动态空间的大小
	size_t n{ 0 };		// 实际的数据元素个数
};

template<typename T> // 体外声明必须要带模板 因为Vector是模板类 类跟模板类的不同就是泛型 T就是传递的类型其他基本一样
Vector<T>::Vector(int cap) :date{ new T[cap] }, n{ 0 }{
	if (date) {
		capacity = cap;
	}
}

template<typename T>
Vector<T>::Vector(const Vector& vec) :Vector{ vec.capacity } { // 在这里先调用构造函数在 拷贝构造函数模板
	if (!date)
		return;
	n = vec.n;
	for (size_t i = 0; i < n; i++) {	// 拷贝值 传递过来的是老对象的值 赋给新对象值 this
		date[i] = vec.date[i];
	}
}

template<typename T>
T& Vector<T>::operator[](size_t index) { // 下标重载运算符模板  可以调用const版本
	if (index >= n)
		throw"下标非法";
	return date[index];
}

template<typename T>
const T& Vector<T>::operator[](size_t index)const { // const 重载  注意之前说到的const_cast<T&>a 可以出去const形  这样就可以调用非const上面的同样模板下标函数了
	if (index >= n)			// 还有std::as_const 在头文件<utility> 作用可以将一个非const对象强制转换成const  const_cast<T&>a 是移除const性
		throw"下标非法";		// 这个就调用不了非const版本 解决方法如下
	return date[index];
}

template<typename T>
T& Vector<T>::operator[](size_t index){
	return const_cast<T&>(std:: as_const(*this)[index]);  // 将有const性 转为无const性
}

template<typename T>
Vector<T>& Vector<T>::operator=(const Vector& rhs) { //rhs 是a 前面&是b
	if (&rhs != this) { // 数据不同 
		Vector<T> ret(rhs); // 调用拷贝函数 让ret值都更新
		T* temp = ret.date;	// 当然交换也可以用标准库 std::swap(data,ret.data);
		ret.date = date;	// 更新本数据this
		date = temp;
		n = ret.n;
		capacity = ret.capacity;
	}
	return *this;	// 返回对象引用
}

template<typename T>
bool Vector<T>::push_back(const T&e) {
	if (capacity == n) {	//空间已满
		T* temp = new T[2 * capacity];
		if (!temp)
			return false;
		capacity *= 2;
		for (size_t i{}; i < n; ++i)
			temp[i] = date[i];		//吧date数据赋给temp 指针就是数组
		delete[] date;				// 删除date
		date = temp;				// 吧扩充了内存赋给date 
	}
	date[n] = e;
	n++;
	return true;
}

template<>
class X<const char*>{ // 模板类的专门化	处理特定类型的 const char* 类型的类
}	// 如果一个模板类里面所有的模板参数都是特定类型的 那么这个专门化实际上是一个类 而不是模板 当然这个类的完整名是X<const char*> 这种模板类称为完全专门类
template<int s = 10> // 这个参数是默认值
class XX<const char*,s>{ // 还有一种是部分专门化 就是专门化部分参数 仍然是一个模板类
}
template<typename T,int s> // 这个s必须出现在T后面
class XX<T* ,s>{ //  将类模板参数专门化 T*  还要注意专门化模板类不能有默认值
} // 在实例化时编译器会根据传递的值选一个最佳的匹配模板类
//如果X<const char*,3>x 会 匹配到template<int s = 10> class XX<const char*,s> 匹配模板 

int main() {
	Vector<int>a;
	for (auto i = 0; i <= 6; i++)
		a.push_back(2 * i + 1); // 添加数据
	a[3] = 30;	
	for (auto i = 0; i != a.size(); i++)
		cout << a[i] << '\t';	
	cout << endl;
	Vector<int>b;	//  如果是同类型就刚才的类创造了一个对象b 如果是新类型就重新构造一个
	b = a;	// 调用赋值运算符 并且把a值赋给b 换成double 会导致类型不匹配
	for (auto i = 0; i != a.size(); i++)
		cout << b[i] << '\t';
	while (true);
	return 0;
}

下面是模板友元类的用法

#include <iostream>

template<typename T>
class X {
public:
	X() = default;
	friend void fun(); // 和普通的友元一样
	friend class A; // 友元类
private:
	int a{ 0 };
};
class A {
public:
	A() = default;
};
void fun() {
	X<int>x;
	X<double>y; // 如果没有 x y对象 就可以用 A对象友元来访问私有成员<< a.a
	X<A>a; //a.a;
	std::cout << a.a << '\t'<<x.a<<'\t'<<y.a<<'\n';
}
// 假如模板类里面有一个友元函数模板 使用的是类模板参数如
//template<typename T>
//class Y {
//	friend Y<T>* g(Y<T>& e); // 这个是一个类模板 友元函数
//}; 列如下

template<typename T>
class Point{
public:
	T x, y;
	Point(const T x, const T y) :x(x), y(y){}
	friend Point<T>* g(Point<T>& e);	// 这个是一个类模板 友元函数
};

template<typename T>
Point<T>* g(Point<T>& e) { //Point<T> 只是声明模板类的方法 实际类型还是Point<T>是对象 如果换成函数就是T
	Point<T>* p = new Point<T>(e); //可以看成Point<T> *p = new Point<T>(e); 调用构造函数
	return p; // 返回对象 类型是一个类 
}

int main() {
	fun();
	Point<int>e(3,4);
	Point<int>* p = g<int>(e); 
	std::cout << p->x << "\t" << p->y << "\n";
	Point<double>x(2, 3);
	auto q = g<double>(x);	//auto q = g<int>(x); 会报错 g <int>不是Point<double>友元 就是类型不一样
	std::cout << q->x << "\t" << q->y << "\n";	// 因为模板类是什么类型 类函数就是什么类型 又没特殊定义
	while (true);
	return 0;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值