泛型编程之类模版

一.概念

类模版和函数模版的定义和使用类似,上篇博客已经介绍了函数模版,有时,有两个或者类,其功能是相同的,仅仅是数据类型不同,如下面语句声明了一个类


注意:1.类模版用于实现所需数据的类型参数化

            2.类模版在表示如数组,表,图等数据结构显得提别重要

            3.这些数据结构表示和算法不收所包含的元素类型的影响

二.单个类模版语法

看如下代码:

template <typename T>
class A
{
private:
	T a;
public:
	A(T a)
	{
		this->a = a;
	}
	void print()
	{
		cout << "a=" << a << endl;
	}
};
void test(A<int> &n)//类模版做函数参数的用法
{
	n.print();
}
int main()
{
	//用模版类生成具体的类,用具体的类生成具体的对象
	{
		A<int> c1(10);
		c1.print();
		test(c1);
	}
	{
	A<double> c1(99.9);
	c1.print();
    }   
	system("pause");
	return 0;
}

三.继承中的类模版语法

1.从模版类派生一个普通类

template <typename T>
class A
{
protected:
	T a;
public:
	A(T a)
	{
		this->a = a;
	}
	void print()
	{
		cout << "a=" << a << endl;
	}
};
//类模版派生时,需要具体化模版类,C++编译器需要知道父类的数据类型具体是什么样子的
//要知道父类所占的内存大小是多少,只有数据类型固定下来,否则不知道怎么分配内存
class B :public A<int>
{
private:
	int b;
public:
	B(int a, int b) :A<int>(a)
	{
		this->b = b;
	}
	void print1()
	{
		cout << "a=" << a << "  b="<<b << endl;
	}
};
int main()
{
	B c1(10, 20);
	c1.print1();
	system("pause");
	return 0;
}

2.从模版类派生模版类

template <typename T>
class A
{
protected:
	T a;
public:
	A(T a)
	{
		this->a = a;
	}
	void print()
	{
		cout << "a=" << a << endl;
	}
};
template <typename T>
class B :public A<T>
{
private:
	T b;
public:
	B(T a b) :A<T>(a)
	{
		this->b = b;
	}
	void print()
	{
		cout << "b="<<b << endl;
	}
};
int main()
{
	B<int> c1(1, 2);
	c1.print();
	system("pause");
	return 0;
}
四.类模版语法知识体系梳理

1.所有类模版函数写在类内部

template <typename T>
class complex
{
private:
	friend ostream& operator<<(ostream &out, const complex &n)//写在类内部没有问题,等会写在类外部就会出问题。等会看下个代码
	{
		{
			out << "a=" << n.a << " b=" << n.b << endl;
			return out;
		}
	}
	friend complex mysub(const complex &n, const complex&m)
	{
		complex c1(n.a - m.a, n.b - m.b);
		return c1;
	}
	T a;
	T b;
public:
	complex(T a, T b)
	{
		this->a = a;
		this->b = b;
	}
	void print()
	{
		cout << "a=" << a << "  b=" << b << endl;
	}
	complex operator+(const complex &n)
	{
		complex c1(this->a + n.a, this->b + n.b);
		return  c1;
	}
};
int main()
{
	//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
	complex <int>c1(1, 2);
	complex<int> c2(2, 4);
     complex<int> c3=c1 + c2;
	 cout << c1 + c2;
	 c3.print();
	 cout << mysub(c1, c2);
	 system("pause");
	 return 0;
}

2.所有模版函数都写在类的外部,不过都写在一个文件中,比如.cpp文件

template <typename T>
class complex
{
private:
	friend ostream& operator<<(ostream &out, const complex &n)
	{
			out << "a=" << n.a << " b=" << n.b << endl;
			return out;
	}
	friend complex mysub(const complex &n, const complex&m)
	{
		complex c1(n.a - m.a, n.b - m.b);
		return c1;
	}
	T a;
	T b;
public:
	complex(T a, T b);
	void print();
	complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
	this->a = a;
	this->b = b;
}
template <typename T>
void complex<T>::print()
{
		cout << "a=" << a << "  b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
	complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
	return  c1;
}
int main()
{
	//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
	complex <int>c1(1, 2);
	complex<int> c2(2, 4);
     complex<int> c3=c1 + c2;
	 cout << c1 + c2;
	 c3.print();
	 system("pause");
	 return 0;
}

现在还没有将友元函数写在外面,代码没有任何问题,接下来将友元也写在外面

template <typename T>
class complex
{
private:
	friend ostream& operator<<(ostream &out, const complex &n);
	friend complex mysub(const complex &n, const complex&m)
	{
		complex c1(n.a - m.a, n.b - m.b);
		return c1;
	}
	T a;
	T b;
public:
	complex(T a, T b);
	void print();
	complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
	this->a = a;
	this->b = b;
}
template <typename T>
void complex<T>::print()
{
		cout << "a=" << a << "  b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
	complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
	return  c1;
}
template <typename T>
ostream& operator<<(ostream &out, const complex<T> &n)
{
	out << "a=" << n.a << " b=" << n.b << endl;
	return out;
}
int main()
{
	//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
	complex <int>c1(1, 2);
	complex<int> c2(2, 4);
     complex<int> c3=c1 + c2;
	 cout << c1 + c2;
	 c3.print();
	 system("pause");
	 return 0;
}
程序一跑就出问题

这是为什么呢?
因为:和函数模版的机制有问题,因为两次编译生成的函数头不一样。


template <typename T>
class complex
{
private:
	friend ostream& operator<<<T>(ostream &out, const complex<T> &n);
	friend complex mysub(const complex &n, const complex&m)//此函数刚才忘记添加,自己加上即可
	{
		complex c1(n.a - m.a, n.b - m.b);
		return c1;
	}
	T a;
	T b;
public:
	complex(T a, T b);
	void print();
	complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
	this->a = a;
	this->b = b;
}
template <typename T>
void complex<T>::print()
{
		cout << "a=" << a << "  b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
	complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
	return  c1;
}
template <typename T>
ostream& operator<<(ostream &out, const complex<T> &n)
{
	out << "a=" << n.a << " b=" << n.b << endl;
	return out;
}
int main()
{
	//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
	 complex <int>c1(1, 2);
	complex<int> c2(2, 4);
     complex<int> c3=c1 + c2;
	 //c1 << cout;//     complex <int>c1(1, 2);
	 operator<<(cout, c1);
	 c3.print();
	 system("pause");
	 return 0;
}

所以说不要滥用友元函数~一般情况下左移和右移运算符重载用友元函数,其余的尽量不要用不然就会出错,不然我们继续往下看

接下来我们将这个函数

	friend complex mysub(const complex &n, const complex&m)
		{
			complex c1(n.a - m.a, n.b - m.b);
			return c1;
		}

弄到模版类外面,看看是什么样的

template <typename T>
class complex
{
private:
	friend ostream& operator<<<T>(ostream &out, const complex<T> &n);
	friend complex mysub(const complex &n, const complex&m);
	T a;
	T b;
public:
	complex(T a, T b);
	void print();
	complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
	this->a = a;
	this->b = b;
}
template <typename T>
void complex<T>::print()
{
		cout << "a=" << a << "  b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
	complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
	return  c1;
}
template <typename T>
ostream& operator<<(ostream &out, const complex<T> &n)
{
	out << "a=" << n.a << " b=" << n.b << endl;
	return out;
}
template <typename T>
complex<T> mysub(const complex<T> &n, const complex<T>&m)
{
	complex c1(n.a - m.a, n.b - m.b);
	return c1;
}
int main()
{
	//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
	 complex <int>c1(1, 2);
	 complex<int> c2(2, 4);
     complex<int> c3=c1 + c2;
	 cout << mysub(c1,c2);
	 c3.print();
	 system("pause");
	 return 0;
}

一样会出错,怎么解决呢?

友元函数如果不是实现函数重载,写在类外,需要进行类的前置声明和函数的前置声明

如下:


  代码如下:

template <typename T>
class complex;
template<typename T>
complex<T> mysub(const complex<T> &n, const complex<T>&m);
template <typename T>
class complex
{
private:
	friend ostream& operator<<<T>(ostream &out, const complex<T> &n);
	friend complex<T> mysub<T>(const complex<T> &n, const complex<T>&m);
	T a;
	T b;
public:
	complex(T a, T b);
	void print();
	complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
	this->a = a;
	this->b = b;
}
template <typename T>
void complex<T>::print()
{
		cout << "a=" << a << "  b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
	complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
	return  c1;
}
template <typename T>
ostream& operator<<(ostream &out, const complex<T> &n)
{
	out << "a=" << n.a << " b=" << n.b << endl;
	return out;
}
template <typename T>
complex<T> mysub<T>(const complex<T> &n, const complex<T>&m)
{
	complex<T> c1(n.a - m.a, n.b - m.b);
	return c1;
}
int main()
{
	//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
	 complex <int>c1(1, 2);
	 complex<int> c2(2, 4);
     complex<int> c3=c1 + c2;
	 cout << mysub(c1,c2);
	 c3.print();
	 system("pause");
	 return 0;
}

3.所有模版函数都写在类的外部,不过都写在.h;.cpp文件中

就是分文件写,这里就不多做介绍了。

总之一句话,不要乱用友元函数~
五.类模版中的static关键字

看如下代码:

template <typename T>
class A
{
public:
	static T a;
};
template <typename T>
T A<T>::a = 0;
int main()
{
	{
		A<int> c1, c2, c3;
		c1.a++;
		c2.a++;
		c3.a++;
		cout << A<int>::a << endl;
	}
	{
	  A<char> c1, c2, c3;
	  c1.a = 'a';
	  c2.a++;
	  c3.a++;
	  cout << A<char>::a << endl;
    }
	system("pause");
	return 0;
}

各自用自己static 变量~

以上就是类模版的基本用法!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值