C++泛型编程学习(1)

17 篇文章 1 订阅

泛型编程的核心是使用 模版, 模板分为函数模板和类模板


函数模板:

|| 函数模板:构建一种可以接受任意数据类型参数来执行内部逻辑的函数

语法:
template  --- 声明即将创建函数模板
<typename T>  // <class T>  --- typename或class
T ---- 指定的通用数据类型,通常情况都用T
template<typename T>  // template<class T>
void func (T  a) {
}

|| 函数模板的调用:1,自动进行类型推导,直接放进实参。2,手动类型声明

|| 调用时注意事项:(有关T --通用数据类型的指定)
// 使用函数模板时T必须被指明类型,且会被自动推导出一致的类型

1,调用函数模板进行自动类型推导时,因为缺少像普通函数一样的隐式类型转换
机制,T只能代表一个数据类型,即直接放入的参数数据类型必须一致
2,调用函数模板时,如函数不需要参数,那也必须指明T的数据类型
template<typename T>
void func(T a){
	test01()
}

//其调用方式!
>>func<int>()

|| 函数模板也可以发生重载

|| 重载时,普通函数与函数模板的调用规则

1,如果函数模板和普通函数都可以实现,优先调用普通函数
但如果普通函数中的参数匹配度不高(例如int形参却传入char实参,可以但匹配度不高)这时优先调用函数模板
但如果调用时使用了“空模板参数列表(即尖括号)”来强制调用函数模板,时优先调用函数模板
void myPrint(int a, int b)
{
	cout << "调用的普通函数" << endl;
}

template<typename T>
void myPrint(T a, T b) 
{ 
	cout << "调用的模板" << endl;
}

template<typename T>
void myPrint(T a, T b, T c) 
{ 
	cout << "调用重载的模板" << endl; 
}

|| 模板的局限性:在传入非内置数据类型(数组,自定义类等)时,函数逻辑一样正确但是无法正常执行。需要为特定类型提供具体化模板(即重载)

|| 具体化语法:

template<typename T>
bool myCompare(Person &p1, Person &p2){}

template<> bool myCompare(Person &p1, Person &p2){}

类模板:

|| 类模板语法(在声明模板template后面加类即类模板)

template<typename NameType, typename AgeName>
class ClassName{};

|| 类模板与函数模板在调用上的区别:

1,类模板使用只能用显示指定类型方式
2,类模板中的模板参数列表可以有默认参数

|| 类模板中成员函数的晚构建(不是晚绑定!)
类模板中的成员函数,并不是一开始就创建的,而是在成员调用时再生成(出现相关错误后,编写过程不会报错,但在编译时,即成员函数调用创建,就会报错)

|| 由类模板中函数晚构建引发的问题:分文件编写时,只包含类模板的.h头文件将无法链接到.cpp文件,头文件看到了声明也不会去链接!

|| 分文件问题的解决方式:

1,直接包含.cpp文件 (.cpp文件中也是有.h头文件的)   --- 很少用
2,将.h .cpp 文件一起写入一个 .hpp文件中  (.h + .cpp)

|| 类模板对象做函数参数的传入方式 — 需要指明类模板对象中的T

一共有三种传入方式:第一种最常用!
   √ 1,直接传入指定类型后的对象 // func(Person<string, int> &p) √
	 2,传入类的参数模板化后的对象 // func(Person<T1, T2> &p)
	 3,传入整个类模板化后的对象 // func(T &p)
void printPerson1(Person<string, int> &p) 
{
	p.showPerson();
}
void test01()
{
	Person <string, int >p("孙悟空", 100);
	printPerson1(p);
}

//2、参数模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2>&p)
{
	p.showPerson();
	cout << "T1的类型为: " << typeid(T1).name() << endl;
	cout << "T2的类型为: " << typeid(T2).name() << endl;
}
void test02()
{
	Person <string, int >p("猪八戒", 90);
	printPerson2(p);
}

//3、整个类模板化
template<class T>
void printPerson3(T & p)
{
	cout << "T的类型为: " << typeid(T).name() << endl;
	p.showPerson();

}
void test03()
{
	Person <string, int >p("唐僧", 30);
	printPerson3(p);
}

|| 题外话:当你需要调用的函数需要某些参数传入(作为形参或指明类型等等),但是该函数并没有接受这些参数的接口时。可以创建一个函数(拥有这些接口),再内部调用目标函数

|| 当类模板碰到继承时,需要指定出父类中T:

1,当父类是模板子类不是模板时,子类在声明的时候,要指定出父类中T的
  类型如果不指定,编译器无法给子类分配内存
2,当父类是模板子类也是模板,可以灵活指定出父类中T的类型
template<class T>
class Base{public: T a;}

//法一
class Son1 :public Base<int>

//法二,灵活
template<class T1, class T2>
class Son2 :public Base<T2>

|| 类模板成员函数的类外实现,其实就是函数模板的实现,不过使用作用域类的声明要加<T1, T2>

//构造函数
template <typename T1, typename T2>
Person<T1, T2>::Person(T1 a, T2, b)

//成员函数
template <typename T1, typename T2>
voin Person<T1, T2>::addPerson()

|| 类模板的友元实现:一般使用类内实现,类外实现复杂且易出错


template<class T1, class T2>
class Person
{
	//类模板友元(在函数参数上有文章)  类内实现
	friend void printPerson(Person<T1, T2> & p)
	{
		cout << "姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
	}
	
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值