ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

模板c++

2022-01-28 14:03:56  阅读:130  来源: 互联网

标签:Ty MM void two c++ print 模板


目录

一、模板简介

1、调用函数模板     隐式调用:正常函数传参即可调用     显示调用:函数名<类型名>(参数)

2、函数模板的两种形态:

(1)、 普通函数函数模板  (2) 、类中函数函数模板

3、函数模板特殊写法:(1)缺省写法 (2)存在常量类型写法

二、类模板

三、自定义类型做模板

四、模板的嵌套

五、类模板的特化

局部特化

完全特化 

六、函数模板的重载


一、模板简介

函数模板
模板:把类型作为未知量
声明模板的语法  template<typename _Ty>    注:_Ty只是代号可以替换
(1)引入模板

typename可以替换为class 如可以改写为template<class T>

//实际上两句为一句,只是为了好看才这样写
//template<typename _Ty> _Ty Max(_Ty a, _Ty b)
template<typename _Ty>//下面代码用到未知类型_Ty
_Ty Max(_Ty a, _Ty b)
{
	return a > b ? a : b;
}
//多模板
template<typename _Ty1,typename _Ty2>
void print( _Ty1 a, _Ty2 b)
{
	cout << a << b << endl;
}

1、调用函数模板
     隐式调用:正常函数传参即可调用
     显示调用:函数名<类型名>(参数)

//使用的就是上面的函数   
 //隐士调用
	cout << Max(1, 2) << endl;
	cout << Max("s", "sad") << endl;
	//显示调用  注意类型的匹配
	cout << Max<string>("as", "sd");
	print<string, string>("asa", "fd");

2、函数模板的两种形态:

(1)、 普通函数函数模板  (2) 、类中函数函数模板

普通函数模板就是之前的例子,下面的是类中函数模板

注:类外实现要写完整

class MM
{
public:
	template<class _Ty> void print(_Ty data)
	{
		cout << data;
	}//本质就是一行 为了好看会把代码拆开来 类外实现要写写全
	template <class _Ty>void printData(_Ty data);

};
template <class _Ty>void MM::printData(_Ty data)
{
	cout << data;
}
//隐式调用
    MM mm;
	mm.printData(1234);

3、函数模板特殊写法:(1)缺省写法 (2)存在常量类型写法

(1)缺省写法

template<typename _Ty1, typename _Ty2=int>
void print2(_Ty1 one, _Ty2 two)
{
	cout << one << "\t" << two << endl;
}
int main()
{
//缺省:可以不传类型 但参数不可少 
//函数模板显示调用
	print2<string>("as", 123);
	print2("123", 123);
return 0;
}

(2)存在传常量情况        不能传变量只能传常量

做了缺省可以隐式调用 否则必须显示调用

template<class _Ty1,size_t size>//size_t无符号整形别名
void printArray(_Ty1 array)
{
	for (int i = 0;i < size;i++)//size可以直接使用
	{
		cout << array[i];
	}
}
int main()
{
//存在传常量的情况 做了缺省可以隐式调用 否则必须显示调用
	int array[3] = { 1,2,3 };
	printArray<int*,3>(array);
	return 0;
}

二、类模板

声明:template<class _Ty>
         class MM{};
         只要被修饰了就是模板类,不管有没有使用位置未知类型
         类模板的调用(类外实现,继承,子类构造函数)
         必须要显示调用
        类模板不是一个实际类型,所以所有用到类名的地方都要使用:类名<未知类型>方法使用
   多文件中,类模板的声明和实现要在一起,不能分开写

注意:1类外实现的写法变为了MM<_Ty>::

       2继承的时候给父类赋值的写法

        3 定义对象的写法

template<class _Ty>
class MM//准备一个父类
{
public:
    MM() {}
    MM(string name):name(name) {}
    void print();
protected:
    string name;
};
template<class _Ty>
void MM<_Ty>::print()//注意这里的声明变为了MM<_Ty>::
{
    cout << "类模板" << endl;
}
//子类
template<class _Ty>
class Girl :public MM<_Ty>
{
public://子函数构造函再给父类赋值时需要加<_Ty>
    Girl(string name) :MM<_Ty>(name) {}
protected:
};

template<class _Ty1,class _Ty2>
class Data
{
public:
    Data(_Ty1 one, _Ty2 two) :one(one), two(two) {}
    void print();
protected:
    _Ty1 one;
    _Ty2 two;
};
template<class _Ty1, class _Ty2>
void Data<_Ty1, _Ty2>::print()
{
    cout << one << endl << two << endl;
}

调用

int main()
{
    //必须采用显示调用
    MM<int> mm;
    Girl<int> g("adas");
    g.print();
    Data<string, int> n("qwe", 21);
    n.print();
	return 0;
}

三、自定义类型做模板

关键在于运算符的重载   

//准备一个数据类

class MM
{
public:
	MM(string name, int age) :name(name), age(age) {}
	friend ostream& operator<<(ostream& out,const MM& mm)
	{
		out << mm.name << "\t" << mm.age << endl;
		return out;
	}
	bool operator > (MM& mm)const 
	{
		return this->age>mm.age;
	}
protected:
	string name;
	int age;
};
template<class _Ty>
void print(_Ty one)
{
	cout << one;
}

template<class _Ty>
_Ty Max(_Ty a, _Ty b)
{
	return a > b ? a : b;
}

int main()
{
	//函数模板传入自定义类型
	print(MM("asds", 123));
	MM x("asd", 13);
	MM s("qwe", 17);
	MM result=Max(x, s);//Max<MM>()
	cout << result;
    return 0;
}

 以链表为例存入自定义数据类型的数据

//类模板
template<class _Ty>
class Node
{
public:
	Node(_Ty data, Node<_Ty>* next) :data(data), next(next) {}
	_Ty getData()
	{
		return data;
	}
	Node<_Ty>* getNext()
	{
		return next;
	}
protected:
	_Ty data;
	Node<_Ty>* next;
};
template<class _Ty>
class List
{
public:
	List()
	{
		headNode = nullptr;
	}
	void insertList(_Ty data)
	{
		headNode = new Node<_Ty>(data, headNode);
	}
	void printList()
	{
		Node<_Ty>* pMove = headNode;
		while (pMove != nullptr)
		{
			cout << pMove->getData() << endl;
			pMove = pMove->getNext();
		}
		cout << endl;
	}
protected:
	Node<_Ty>* headNode;
};

调用·

int main()
{
    List<int> list;
	list.insertList(1);
	list.insertList(2);
	list.printList();
//这里的MM就是一开始准备的数据类,其中<<在MM类中做了运算符重载
	List<MM> list1;
	list1.insertList(MM("as", 12));
	list1.insertList(MM("qw", 16));
	list1.printList();
    return 0;
}

四、模板的嵌套

//准备两个类模板MM和Data
template<class _Ty1,class _Ty2>
class MM
{
public:
	MM(_Ty1 one, _Ty2 two) :one(one), two(two) {}
	friend ostream& operator<<(ostream& out, const MM& mm)
	{
		out << mm.one << " " << mm.two << endl;
		return out;
	}
protected:
	_Ty1 one;
	_Ty2 two;
};
template<class _Ty1, class _Ty2>
class Data
{
public:
	Data(_Ty1 one, _Ty2 two) :one(one), two(two) {}
	void print()
	{
		cout << one << two;
	}
protected:
	_Ty1 one;
	_Ty2 two;
};


template<class _Ty>
void print(_Ty data)
{
	cout << data << endl;
}
int main()
{
    //隐士调用
	print(MM<string, int>("asd", 123));
    //显示调用
	print<MM<string, int>>(MM<string, int>("asd", 123));

		Data<MM<string, int>, MM<double, int>>//显示调用
		data(MM<string, int>("ASD", 123), //定义data并赋值
			MM<double, int>(12.3, 12));
	data.print();
	return 0;
}

五、类模板的特化

初始的类模板

template<class _Ty1,class _Ty2>
class MM
{
public:
	MM(_Ty1 one, _Ty2 two) :one(one), two(two) {}
	void print()
	{
		cout << one << " "<<two << endl;
	}
protected:
	_Ty1 one;
	_Ty2 two;
};

局部特化

两个未知类型变为一个未知类型  称为局部特化或特殊化
特殊化(针对特殊化数据特殊化处理) 如传入对象在打印时更改打印方式调用方法

注意写法:特化产生的类类名要用:类名<类型>方式使用

class MM<_Ty,_Ty> //特化产生的类类名要用:类名<类型>方式使用
{
public:
	MM(_Ty one, _Ty two) :one(one), two(two) {}
	void print()
	{
		one.print();
		two.print();
	}
protected:
	_Ty one;
	_Ty two;
};
class Data
{
public:
	Data(int one, int two) :one(one), two(two) {}
	void print()
	{
		cout << one << "特殊化 " << two << endl;
	}
protected:
	int one;
	int two;
};
int main()
{
	MM<Data, Data> mm3(Data(1, 2), Data(2,3));
	mm3.print();
return 0;
}

完全特化 依旧是模板类 类型变为已知 元组容器

template<>
class MM<string, string>
{
public:
	MM(string one, string two) :one(one), two(two) {}
	void print()
	{
		cout << one << "完全特化 " << two << endl;
	}
protected:
	string one;
	string two;
};
int main()
{
    MM<string, string> mm4("sad", "zxc");
	mm4.print();
	return 0;
}

六、函数模板的重载

  隐士调用优先调用类型一致的函数
  字符传优先解析为char*

隐士调用中当2个模板同时成立,优先调用类型相似度高的

void print(int a, string b)
{
	cout << "普通函数" << endl;
}
template <class _Ty1,class _Ty2>
void print(_Ty1 a, _Ty2 b)
{
	cout << "两个类型" << endl;
}
template<class _Ty>
void print(_Ty a, _Ty b)
{
	cout << "一个类型 " << endl;
}
int main()
{
	//显示调用  100%调用模板
	//隐士调用优先调用类型一致的函数
	//字符传优先解析为char*
	print(12, string("qwe"));
	print(12, "qwe");
	//隐士调用中当2个模板同时成立,优先调用类型相似度高的
	print(12, 12);
}

标签:Ty,MM,void,two,c++,print,模板
来源: https://blog.csdn.net/weixin_61438881/article/details/122720659

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有