模板c++

目录

一、模板简介

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);
}

上一篇:Serverless计算


下一篇:MySQL 连接错误Can't connect to MySQL server on (61)