C++模板初学(笔记自用

C++模板初学(笔记自用

如果发现代码跑不动,请检查标点符号是否是英文,我虽然复盘的时候修改了一部分,但是有点但是未能全部修改

模板的概念:建立通用的模具,提高复用性,将类型参数化
模板的通用并不是万能的,只是一个框架,不能直接使用
(另一种编程思想就是面向对象)
C++的泛型编程思想主要用到的就是模板
C++提供两种模板机制,函数模板和类模板

函数模板的作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体定制,用一个虚拟的类型代表
语法如下;

template<typename T>
函数声明或定义

template是声明创建模板
typename表示其后面跟着的符号是一种数据类型,可以用class代替
T表示通用的的数据类型,名称可以替换,通常为大写字母

有两种方式使用函数模板
第一种:自动类型推导

template<typename T>
void mySwap(T&a,T&b)
{
   T temp=a;
   a=b;
   b=temp;
}
int main()
{
int a=10;
int b=20;
mySwap(a,b);
//让编译器自动找出对应的类型
}

第二种:显示指定类型

mySwap<int>(a,b);

注意:自动类型推导,

必须(无参时也要知道T的类型才能运行)

推导出一致的数据类型T才可以使用
模板必须要确定出T的数据类型才可以使用

当数组名传入到函数作为参数时,会被退化为指向首元素的指针

#include<iostream>
#include<fstream>
#include<string>
#include<vector>
using namespace std;

template<typename T>
void myswap(T&a,T&b)
{
	T temp=a;
    a=b;
    b=temp;
	
}

template<typename T>
void arryswap(T arr[],int len)
{
	int i=0;
	for(;i<len;i++)
	{
	   for(int j=i+1;j<len;j++)
	   {
		  int max=i;
		  if(arr[max]<arr[j])
		  {
			  max=j;
		  }
		  if(max!=i)
		  {
			  myswap(arr[i],arr[max]);
		  }
	    }
    }
}
int main() {
char arr[]="aysidnb";
int num=sizeof(arr)/sizeof(char);
arryswap(arr,num);
cout<<arr<<endl;
//这里的输出排序后的数组也可以使用模板来输出
	return 0;
}

普通函数与函数模板的区别
1,普通函数调用时可以发生自动类型转换(隐式类型转换,类似把char类型的数据作为形参为int的函数参数,会自动将char的字符变为ASCII码)
2,函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换。
3,如果利用显示指定类型的方式,可以发生隐式类型转换

调用规则
1,如果函数模板和普通函数都可以实现,优先调用普通函数(两者可同名/重载
2,可以通过空模板参数列表来强制调用函数模板(函数名后加<>)
3,函数模板也可以发生重载
4,如果函数模板可以产生更好的匹配,优先调用函数模板(理解为不需要隐式类型转换的优先)
**注意:既然已经提供了函数模板,最好不要再提供普通函数,否则容易出现二义性 **

模板的局限性
模板的通用性并不是万能的,但c++提供模板的重载,可以为这些特定的类型提供具体化的模板

具体化实现
模板:

tmeplate<typename T>
bool myCompare(T&a,T&b){//函数实现的代码};

具体化:

 template<> bool myCompare(person  &p1,person &p2){//具体代码实现};

注意:学习模板并不是为了写模板,而是为了在STL能够运用系统提供的模板

类模板
作用:建立一个通用类,类中的成员,数据类型可以不具体指定,用一个虚拟的类型来代表。

语法:

template<typename T>//语法和函数模板一样,只是template后面跟的改成一个类

例子:

#include<iostream>
#include<fstream>
#include<string>
#include<vector>
using namespace std;



template<class NameType, class AgeType>
class person
{
public:
	person(NameType name, AgeType age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	NameType m_name;
		AgeType m_age;

	void show()
	{
		cout << this->m_name << this->m_age << endl;
	}
};
void test01()
{
	person<string, int>p("moumou", 19);
	p.show();

}
int main() {


	test01();

	return 0;

类模板与函数模板的区别
1,类模板没有自动类型推导的使用方式
2,类模板在模板参数列表中可以用默认参数
3,类模板在动态分配数组中会很有用

类模板中使用默认参数如下

template<class NameType,class AgeType>
class person
{
public:
      person(NameType name,AgeType age)
      {
      this->m_name=name;
      this->m_age=age;
      } 
	  NameType m_name;
      AgeType m_age;
	void show()
	{
		cout <<this->m_name << this->m_age << endl;
	}
};
void test01()
{
	person<string, int>p("moumou", 19);
	p.show();

}

类模板中成员函数创建 时机
1,普通类中的成员函数一开始就可以创建
2,类模板中的成员函数在调用时才创建

类模板上的参数可以是其他的类

类模板对象做函数参数
1,指定传入类型-直接显示对象的数据类型(使用比较广泛

template<class T1,class T2>
class person
{
public:
      person(class T1,class T2)
      {
      this->m_name=name;
      this->m_age=age;
      } 
      T1 m_name;
      T2 m_age;
      void showprint()
      {//此处省略输出代码
      };
}; 

void printPerson1(person<string,int >&p)
{
    p.showprint();
};
void test01()
{
   person<string,int>p("moumou",18);
   printPerson1(p); 
}

2,参数模板化-将对象中的参数变为模板后进行传递

template<class T1,class T2>
void printPerson2(person<T1,T2>&p){省略的代码};
//**注意,可以用typeid(T1).name()查看编译器自动推导的类型**

3,整个类模板化-将这个对象类型模板化后传递

template<class T>
void printPerson3(T &p)
{};
//但规则越多,越容易出现错误

当类模板遇到继承时,需要注意
1,当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中的T的类型
2,如果不指定,编译器将无法给子类分配内存
3,如果想灵活指定出父类中的T的类型,子类也需变为类模板

template<class T>
class base
{
   T m;
};
class son :public base<int>
{};

如果想要灵活指定则

template<class T1,class T2>
class son2:public base<T2>
{
T1 obj; 
};

小结:如果父类是类模板,子类需要指定出父类中的T的数据类型

类模板中的成员函数类外实现
template<class T1, class T2>
class person
{
public:
    person(T1 name, T2 age);
    T1 m_name;
        T2 m_age;
        void showprint();
};
//构造函数的类外实现
template<class T1, class T2>
person<T1,T2>::person(T1 name,T2 age)
{
    this->m_name = name;
    this->m_age = age;
}
//成员函数的类外实现
template<class T1, class T2>
void person<T1, T2>::showprint()
{
    cout << this->m_name << this->m_age << endl;
}
void test01()
{
    person<string, int>p("moumou", 18);
    p.showprint();
}

小结:类模板中的成员函数类外实现时,需要加上模板参数列表

类模板份文件编写

如果类模板中成员函数创建时机是在调用阶段,导致份文件编写时链接不到
解决方法如下:
1,直接包含.cpp源文件
指不再实现#include<moumou.h>
而是将后缀改为.cpp,因为cpp中已经包含了.h

2,将声明和实现写道同一文件中,并更改猴嘴名为.hpp,hpp是约定的名字,并不是强制
第二种解决方法就是将.h和.cpp中的内容写到一起,将后缀名改为.hpp文件
而且该方法为主流

类模板与友元(该部分内容存疑

全局函数类内实现,直接在类内声明友元即可
全局函数类外实现,需要提前让编译器知道全局函数的存在
当私有函数加friend后就是全局函数
以下为类内实现

template<class T1, class T2>
class person
{
    friend void showprint(person<T1, T2>p)
    {
        cout << p.m_name << p.m_age << endl;
    };
    public:
        person(T1 name,T2 age)
        {
            this->m_name = name;
            this->m_age = age;
        }
    private:
        T1 m_name;
            T2 m_age;

    };

void test01()
{
    person<string, int>p("moumou", 18);
    showprint(p);
}

类外实现

template<class T1,class T2>
class person
{
//加空模板参数列表
//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在
//即将实现放到类前,但类要在最前面先声明,且声明该类是类模板
//**需要提前告诉这个是模板 **

//包含一个可能,即直接在该友元前声明该函数是模板
//可行,需在友元前声明该函数为模板函数,并去除<>恢复成普通成员函数
template<class T1, class T2>
class person;

template<class T1,class T2>
void showprint(person<T1, T2>p);

template<class T1, class T2>
class person
{
   
    friend void showprint<>(person<T1, T2>p);
    public:
        person(T1 name,T2 age)
        {
            this->m_name = name;
            this->m_age = age;
        }
    private:
        T1 m_name;
            T2 m_age;

    };
template<class T1,class T2>
void showprint(person<T1, T2>p)
{
    cout << p.m_name << p.m_age << endl;
}

void test01()
{
    person<string, int>p("moumou", 18);
    showprint(p);
}

内容学习自http://yun.itheima.com/course/520.html?bili

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值