C++定制类模板并覆盖类模板中定义的所有成员或指定的成员

目录

一、定制一个类模板,覆盖类模板中定义的所有成员。

1、简述这项工作的大概过程

(1)、定义普通类

(2)、定义模板类

(3)、定制模板类

(4)、main函数

2、定制模板的方法

3、一个不常见的C++语法结构:半角冒号用于构造函数里的初始化列表开始标识符

4、整个过程的实例

5、按单步调试程序,注意并观察实参与形参的匹配

 二、定制一个类模板,覆盖类模板中定义的指定的成员。

 1、定制模板覆盖指定的部分成员的方法

2、整个过程的实例

3、按单步调试程序,注意并观察实参与形参的匹配;

三、总结


         定制模板类后,如果需要扩展模板心累的功能,就要对类模板进行覆盖,使模板类能够完成特殊的功能。

        覆盖操作可以针对整个类模板、部分类模板以及类模板的成员函数,这种覆盖操作称为定制。

        这个过程以案例说明。

一、定制一个类模板,覆盖类模板中定义的所有成员。

1、简述这项工作的大概过程

(1)、定义普通类

  • 定义一个普通类class Date,这个类有3个数据参数int iMonth,iDay,iYear;
  • 在这个普通类里定义构造函数、友元重载运算符<<函数、显示输出函数;

(2)、定义模板类

  • 定义模板类template <class T>  class Set   其中参数t是T类型,即标准数据类型;
  • 定义构造函数并对构造函数初始化。t是形参,数据类型是T,用实参st实例化,当然也可以用intset、dt等实例化;
  • 显示输出函数;

(3)、定制模板类

  • 定制模板类、扩展、专业化模板类template<> class Set<Date>,用Date类型替换T类型;
  • 覆盖 class Set 全部类体;

(4)、main函数

  • Set<int> intset(123);
  •  实例化说明:定义模板类对象,数据类型int(注意用int代替T),定义class Set对象变量intset(用intset代替形参t),给实参intset赋值123并代替形参st;
  •  Set<Date> intset1(123);

  • 实例化说明:定制模板类对象,数据类型Date,定义class Set<Date>对象变量intset1(用intset1代替形参t),给实参intset1赋值123并代替形参st;

2、定制模板的方法

        对模板类的成员函数的特化时要加上template<>;对模板类的成员函数的特化,需要返回值类型与模板匹配;

template <class T> class Set { T display(); };      //声明            
template<> class Set<Date> { Date display(); };     //特化

3、一个不常见的C++语法结构:半角冒号用于构造函数里的初始化列表开始标识符

        这个语法结构在一般的教科书里看不到解释,个别的书里有使用但没有解释。这个语法结构是:半角冒号用于构造函数里的初始化列表开始标识符。

Set(Date st):t(st){}; //这时定义在类里面,如果定义在外面,前面还会有个 set::

//等价与
set(data st)
{
    t = st;
}

        两种用法是等价的,第二种用法更容易理解。

        区别在于,第二种形式 t会多执行一步默认构造函数构造t,再在构造函数体语句块中调用赋值操作符给t再赋一次值。
        另外,对于一些特殊情况必须写在初始化列表里,如引用型属性的初始化。因为那才是初始化,语句块中的是初始化后的再赋值。

4、整个过程的实例

/*定制一个类模板,覆盖类模板中定义的所有成员*/
#include <iostream>
using namespace std;
//定义普通类
class Date												
{
	int iMonth,iDay,iYear;
	/*char Format[128];*/
	public:
	Date(int m=0,int d=0,int y=0)						//定义构造函数
	{
		iMonth=m;
		iDay=d;
		iYear=y;
	}
	friend ostream& operator<<(ostream& os,const Date t)//定义一个友元重载运算符‘<<’用于输出Date类型
	{
		cout << "Month: " << t.iMonth << ' ' ;
		cout << "Day: " << t.iDay<< ' ';
		cout << "Year: " << t.iYear<< ' ' ;
		return os;
		
	}
	void Display()										//定义成员函数
	{
		cout << "Month: " << iMonth;
		cout << "Day: " << iDay;
		cout << "Year: " << iYear;
		cout << endl;
	}
};
//定义类模板,共用一个类模板
template <class T>	
//定义模板类Set,其中参数t是int类型,不能识别Date类型,输入Date类型,警告E0289
class Set												
{
	T t;												//定义类变量
	public:
		Set(T st) : t(st) {}							//定义构造函数,冒号是构造函数里的初始化列表开始的标识Set(T st) {t = st;}
														//t是形参,数据类型是T,用实参st实例化,当然也可以用at、mt实例化
		void Display()									//定义成员函数
		{
			cout << t << endl;
		}
};
//定制新的模板类Set<Date>,覆盖原类参数,共用一个类模板<class T>
//其中参数t是Date类型
//必须增加template<>否则警告C2906: “Set<Date>”: 显式专业化需要“template <>”
template<> class Set<Date>
{
	Date t;												//定义类变量
public:
	Set(Date st): t(st){}								//定义构造函数,冒号是构造函数里的初始化列表开始的标识Set(Data st) {t = st;}
														//t是形参,数据类型是Data,用实参st实例化,当然也可以用at、mt实例化
	void Display()										//定义成员函数
	{
		cout << "Date :" << t << endl;
	}
};

int main()
{
	Set<int> intset(123);
	intset.Display();

	//注意到上面<int>如果替换为<Date>结果就不一样了,再把实参修改为Date类型
	Set<Date> intset1(123);
	intset1.Display();

	Set<Date> intset2(Date(04, 20, 2023));
	intset2.Display();

	Set<Date> dt (Date(04,20,2023));
	dt.Display();

	Set<Date> dt1=Date(04, 21, 2023);
	dt1.Display();
}
/*运行结果
123
Date :Month: 123 Day: 0 Year: 0
Date :Month: 4 Day: 20 Year: 2023
Date :Month: 4 Day: 20 Year: 2023
Date :Month: 4 Day: 21 Year: 2023	*/

5、按单步调试程序,注意并观察实参与形参的匹配

 二、定制一个类模板,覆盖类模板中定义的指定的成员。

 1、定制模板覆盖指定的部分成员的方法

        用类型替换定制模板,用作用域::覆盖指定的成员函数。一般表达式是:

void Set<T>::Display()				//定制新类并覆盖部分成员函数
{
	cout << t << endl;
}
void Set<Date>::Display()			//再定制新类并覆盖部分成员函数
{
	cout << "Date: " << t << endl;
}

         这里只列出了定制类的方法,源类定义详见下面的源码。一般表达式的含义是,定制类分别用实参类型T(基本类型)和实参类型Data(日期类型)代入源类形参,然后根据实参类型的实例化选择对应的定制类输出并显示结果。

2、整个过程的实例

/*定制一个类模板,覆盖类模板中定义的指定的成员*/
#include <iostream>
using namespace std;
class Date							//定义普通类
{
	int iMonth,iDay,iYear;
public:
	Date(int m=0,int d=0,int y=0)	//定义构造函数
	{
		iMonth=m;
		iDay=d;
		iYear=y;
	}
	friend ostream& operator<<(ostream& os,const Date t)//定义有缘运算法<<用于Display(Date)
	{
		cout << "Month: " << t.iMonth << ' ' ;
		cout << "Day: " << t.iDay<< ' ';
		cout << "Year: " << t.iYear<< ' ' ;
		return os;
		
	}
	void Display()					//定义成员函数
	{
		cout << "Month: " << iMonth;
		cout << "Day: " << iDay;
		cout << "Year: " << iYear;
		cout << std::endl;
	}
};
template <class T>					//定义类模板,共用一个类模板
class Set							//定义模板类Set,其中参数t是int类型,不能识别Date类型,输入Date类型,警告E0289
{
	T t;
	public:
		Set(T st) : t(st) {}		//定义构造函数,冒号是构造函数里的初始化列表开始的标识Set(T st) {t = st;}
		void Display();				//定义空成员函数
};
template <class T>					//不可以注释掉
//覆盖类模板中的部分成员:类作用域::成员函数
void Set<T>::Display()				//定制新类并覆盖部分成员函数
{
	cout << t << endl;
}
void Set<Date>::Display()			//再定制新类并覆盖部分成员函数
{
	cout << "Date: " << t << endl;
}
int main()
{
	Set<int> intset(123);			//调用class Set,实参int代入形参T,对象变量intset代入形参st,对象实例123代入形参t,完成实例化
	intset.Display();				//调用第一个覆盖模板类的成员函数void Set<T>::Display()
	
	Set<Date> dt =Date(14,20,2023);	//调用class Date的构造函数->赋值->class Set构造函数
	dt.Display();					//调用第二个覆盖模板类的成员函数void Set<Date>::Display()->友元重载运算符<< ->void Set<Date>::Display()->输出t
}
/*运行结果:
123
Date: Month: 14 Day: 20 Year: 2023	*/

3、按单步调试程序,注意并观察实参与形参的匹配;

三、总结

        根据实参类型定制、特化新类,并根据实参实例化选择对应的类输出结果,是模板类定制的核心奥义。

猜你喜欢

转载自blog.csdn.net/wenchm/article/details/130809610