第九天之类模板语法知识体系梳理

所有的类模板函数写在类的内部

#include "iostream"
using namespace std;


template <typename T>
class Complex
{
public:
	friend Complex MySub(Complex &c1, Complex &c2)
	{
		Complex temp(c1.a - c2.a, c1.b - c2.b);
		return temp;
	}
	friend ostream & operator<<(ostream &out, Complex &c)
	{
		out  << c.a << " + " << c.b << endl;
		return out;
	}
	Complex(T a , T b )
	{
		this->a = a;
		this->b = b;
	}
	//重载+操作符
	Complex& operator+(Complex &c2)
	{
		Complex temp(a+c2.a, b+c2.b);
		return temp;
	}
	//重载<<运算符
	
	

	void printComplex()
	{
		cout << "a: " << a << "b: " << b << endl;
	}
private:
	T a;
	T b;
};

//运算符重载的正规写法
//重载 << >>只能用友元函数,其他的运算符重载有要写成成员函数, 不要滥用友元函数
/*
ostream & operator<<(ostream &out, Complex &c)
{
	out << "c.a: " << c.a << "c.b: " << c.b << endl;
	return out;
}
*/


void main061()
{
	Complex<int> c1(1, 2);
	Complex<int> c2(3, 4);
	//Complex& operator+(Complex &c2);
	Complex<int> c3 = c1 + c2;
	cout << c3 << endl;

	//滥用友元函数案例
	{
		Complex<int> c4 = MySub(c1, c2);
		cout << c4 << endl;
	}

	system("pause");
}

所有的类模板函数写在类的外部,在一个 cpp 中

#define  _CRT_SECURE_NO_WARNINGS 
#include "iostream"
#include <string>

using namespace std;

template <typename T>
class Complex;		//类的前置声明

template <typename T>	
Complex<T> MySub<T>(Complex<T> &c1, Complex<T> &c2);	//非<< >>重载的友元函数的前置声明

template <typename T>
class Complex
{
public:
	friend Complex<T> MySub<T>(Complex<T> &c1, Complex<T> &c2);

	//重载<<运算符  operator<<<T>
	friend ostream & operator<<<T>(ostream &out, Complex &c);
	Complex(T a, T b);
	void printComplex();
	//重载+操作符
	Complex operator+(Complex &c2);

	//Complex operator-(Complex &c2);
	
private:
	T a;
	T b;
};

//构造函数的实现写在了类的外部
template <typename T>
Complex<T>::Complex(T a, T b)
{
	this->a = a;
	this->b = b;
}

template <typename T>
void Complex<T>::printComplex()
{
	cout << "a: " << a << "b: " << b << endl;
}

//成员函数 实现+运算符重载
template <typename T>
Complex<T> Complex<T>::operator+ (Complex<T> &c2)
{
	Complex temp(a + c2.a, b + c2.b);
	return temp;
}

/*template <typename T>
Complex<T> Complex<T>::operator-(Complex<T> &c2)
{
	Complex<T> temp(a - c2.a, b - c2.b);
	return temp;
}*/

//友元函数实现 重载<<运算符
/*	本质是:模板函数是两次编译生成的,第一次生成的函数头和第二次生成的函数头不一样
	解决方法:	friend ostream & operator<<<T>(ostream &out, Complex &c);
错误	LNK2019	无法解析的外部符号 "class std::basic_ostream<char,struct std::char_traits<char> > &
__cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Complex<int> &)" 
(??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$Complex@H@@@Z),
该符号在函数 _main 中被引用	泛型编程课堂操练	
*/
template <typename T>
 ostream & operator<<(ostream &out, Complex<T> &c)
{
	out << c.a << " + " << c.b << endl;
	return out;
}

 /
 //滥用友元函数
 /*

错误	LNK2019	无法解析的外部符号 "class Complex<int> __cdecl MySub(class Complex<int> &,class Complex<int> &)" 
(?MySub@@YA?AV?$Complex@H@@AAV1@0@Z),该符号在函数 _main 中被引用	

 */
 template <typename T>
 Complex<T> MySub(Complex<T> &c1, Complex<T> &c2)
 {
	 Complex<T> temp(c1.a - c2.a, c1.b - c2.b);
	 return temp;
 }

//运算符重载的正规写法
//重载 << >>只能用友元函数,其他的运算符重载有要写成成员函数, 不要滥用友元函数
/*
ostream & operator<<(ostream &out, Complex &c)
{
out << "c.a: " << c.a << "c.b: " << c.b << endl;
return out;
}
*/


void main()
{
	Complex<int> c1(1, 2);
	Complex<int> c2(3, 4);
	//Complex& operator+(Complex &c2);
	Complex<int> c3 = c1 + c2;
	cout << c3 << endl;

	//滥用友元函数案例
	{
		Complex<int> c4 = MySub<int>(c1, c2);
		cout << c4 ;
	}

	system("pause");
	return;
}

//构造函数 没有问题
//普通函数 没有问题
//友元函数:用友元函数重载 << >>
// friend ostream& operator<< (ostream &out, Complex &c3) ;
//友元函数:友元函数不是实现函数重载(非 << >>)
//1)需要在类前增加 类的前置声明 函数的前置声明
template
class Complex;
template
Complex mySub(Complex &c1, Complex &c2);
//2)类的内部声明 必须写成:
friend Complex mySub (Complex &c1, Complex &c2);
//3)友元函数实现 必须写成:
template
Complex mySub(Complex &c1, Complex &c2)
{
Complex tmp(c1.a - c2.a, c1.b-c2.b);
return tmp;
}
//4)友元函数调用 必须写成
Complex c4 = mySub(c1, c2);
cout<<c4;

结论:友元函数只用来进行 左移 友移操作符重载。

所有的类模板函数写在类的外部,在不同的.h 和.cpp 中

#include "iostream"
using namespace std;
#include "dem09_Complex.cpp"	//注意:模板类的声明和实现分开写时,此处包含的是.cpp文件,否则会报错找不到函数实现

void main()
{
	
	Complex<int> c1(1, 2);
	Complex<int> c2(3, 4);
	//Complex& operator+(Complex &c2);
	Complex<int> c3 = c1 + c2;
	cout << c3 << endl;

	//滥用友元函数案例
	{
		//Complex<int> c4 = MySub<int>(c1, c2);
		//cout << c4;
	}
	


	system("pause");
	return;
}

要包含.cpp,否则编译不通过

总结

归纳以上的介绍,可以这样声明和使用类模板:

  1. 先写出一个实际的类。由于其语义明确,含义清楚,一般不会出错。
    轻松入门 实战应用 传智播客 C++课程
  2. 将此类中准备改变的类型名(如 int 要改变为 float 或 char)改用一个自己指定的虚拟类型名
    (如上例中的 numtype)。
  3. 在类声明前面加入一行,格式为:
    template <class 虚拟类型参数>
    如:
    template //注意本行末尾无分号
    class Compare
    {…}; //类体
  4. 用类模板定义对象时用以下形式:
    类模板名<实际类型名> 对象名;
    类模板名<实际类型名> 对象名(实参表列);
    如:
    Compare cmp;
    Compare cmp(3,7);
  5. 如果在类模板外定义成员函数,应写成类模板形式:
    template <class 虚拟类型参数>
    函数类型 类模板名<虚拟类型参数>::成员函数名(函数形参表列) {…}

关于类模板的几点说明:

  1. 类模板的类型参数可以有一个或多个,每个类型前面都必须加 class,如:
    template <class T1,class T2>
    class someclass
    {…};
    在定义对象时分别代入实际的类型名,如:
    someclass<int,double> obj;
  2. 和使用类一样,使用类模板时要注意其作用域,只能在其有效作用域内用它定义对象。
  3. 模板可以有层次,一个类模板可以作为基类,派生出派生模板类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值