全面总结C++类模板使用的基础知识_c++模板怎么用(2)

class B
{
public:
void showInfo()
{
cout << “调用B类的成员函数” << endl;
}
};
template
class MyStudy
{
public:
T pre;
//类模板中的成员函数
void show()
{
pre.showInfo();
}
};
void test03()
{
MyStudy* S = new MyStudy();//创建A类属性的类模板对象S
MyStudy* D = new MyStudy();//创建B类属性的类模板对象D
S->show();
D->show();
delete S;//释放堆区指针
delete D;
S = NULL;
D = NULL;
}


        **由于成员属性pre的类型未指定是A类还是B类,所以编译器并不会创建成员函数,无法识别showInfo函数是哪一个类的成员函数。只有我们创建的时候给类模板对象指针指定T类型,这时候调用show方法编译器才会创建成员函数,实现对应的功能。**


运行效果:


![](https://img-blog.csdnimg.cn/b8ae4998ff1c4b3ab0c05714d67afa3b.png)


###  类模板对象做函数参数


**三个形式:**



> 
> 指定传入类型
> 
> 
> 参数模板化
> 
> 
> 整个类模板化
> 
> 
> 


代码演示:



template<class T1,class T2=int>
class Per
{
public:
T1 name;
T2 height;
Per(T1 name, T2 height)
{
this->name = name;
this->height = height;
}
void showInfo()
{
cout << “姓名:” << name << " 身高:" << height << endl;
}
};
//1、指定传入类型
void printInfo(Per<string, int>& p)
{
p.showInfo();
}

//2、参数模板化
template<class T1,class T2>
void printInfo1(Per<T1, T2>& p)
{
p.showInfo();
cout << “T1的类型为:” << typeid(T1).name() << endl;
cout << “T2的类型为:” << typeid(T2).name() << endl;
}
//3、整个类模板化
template
void printInfo2(t & p)
{
p.showInfo();
cout << “t的类型为:” << typeid(t).name() << endl;
}
void test04()
{
Per p(“叶落秋白”, 183);
printInfo§;
}
void test4()
{
Per p(“微凉秋意”, 184);
printInfo1§;
}
void test4a()
{
Perp(“落叶归根”,185);
printInfo2§;
}


    **小结:第一种指定传入类型的方式最为常用,查看自动推导类型可以调用typeid(虚拟类型).name()函数。其实string类型原名特别长,调用typeid函数的时候可以查看,另外也可以直接查看整个类模板化时虚拟类型t的数据类型。**


运行效果:


![](https://img-blog.csdnimg.cn/e6f5f5d1210c403faf2c0d58355e4b39.png)


### 类模板与继承


**类模板的继承不同于普通类的继承。这是因为类模板的属性数据类型事先并未指定,所以子类无法分配内存空间。**


要点:



> 
> 直接继承会提示缺少基类类的参数列表,需要继承的时候在基类后面指定<数据类型>  
>  如果想要灵活指定父类中的T数据类型,子类也要变成类模板
> 
> 
> 


代码示例:



template
class Base
{
public:
Base()
{
cout << “此时父类T的数据类型是:” << typeid(T).name() << endl;
}
T m;
};
//class Son :public Base//这里可以直接指定,不过为了灵活指定,将子类变为类模板
//子类变成类模板
template<class T1,class T2>
class Son :public Base
{
public:
T1 n;
Son() {
cout << “T1的数据类型为:” << typeid(T1).name()<< endl;
cout << “T2的数据类型为:” << typeid(T2).name()<< endl;
}
};
void test05()
{
Son<int,char> s;
}


      **将子类变为类模板的时候可以自由添加子类的属性,这里子类Son的属性是T1类型的n,当然继承的T2属性的m也存在。在继承的时候将T2作为父类的虚拟类型,那么创建子类对象的时候指定的数据类型char就会先传给T2,T2再传给父类的T,那么就完成了灵活指定继承数据类型的工作**


**创建子类对象是会自动调用父类构造,那么就能调用事先设置好的typeid函数来查看由子类指定的父类的虚拟数据类型的具体类型。**


运行效果:


![](https://img-blog.csdnimg.cn/392928f89d364f79ba3373bbc2f55b8d.png)


### **类模板成员函数的类外实现**


**成员函数类外实现需要在加作用域的前提下再加类模板的参数列表**


代码演示:



template<class T1, class T2>
class Person
{
public:
T1 name;
T2 height;
Person(T1 name, T2 height);//构造函数声明
void showInfo();//showInfo函数声明
};
//构造函数类外实现
template<class T1,class T2>
Person<T1,T2>::Person(T1 name, T2 height)
{
this->height = height;
this->name = name;
}
template<class t1, class t2>
void Person<t1,t2>::showInfo()
{
cout << “姓名:” << name << " 身高:" << height << endl;
}
//成员函数类外实现
void test06()
{
Person<string, int> p(“叶落秋白”,184);
p.showInfo();
}


         **虽然在加作用域的前提下加了类模板的参数列表,但是编译器并不认识那些虚拟类型,所以还需要在其上面紧跟着加上template关键字来声明虚拟类型。**


### 类模板的分文件编写



> 
> 问题所在:  
>  由于**类模板成员函数在调用时才创建**,只包含头文件,再函数调用时会出现无法解析的命令  
>  解决方案:  
>   1、包含源文件(.cpp)不常用  
>   2、常将头文件和源文件写进一个文件里,文件**后缀名改为.hpp**,约定的格式
> 
> 
> 


示例:



//person.hpp文件内容
#pragma once
#include
using namespace std;
template<class T1, class T2>
class Person
{
public:
T1 name;
T2 height;
Person(T1 name, T2 height);
void showInfo();
};
//构造函数类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 height)
{
this->height = height;
this->name = name;
}
template<class t1, class t2>
void Person<t1, t2>::showInfo()
{
cout << “姓名:” << name << " 身高:" << height << endl;
}
//调用的文件内容
#include"person.hpp"
void test07()
{
Person<string, int> p(“叶落秋白”, 184);
p.showInfo();
}


      **将头文件声明和源文件实现全部写在一个头文件里并将头文件名改为.hpp就能解决类模板的分文件编写出现的问题了。**


### 类模板和友元


特点:



> 
> 全局函数类内实现,直接在类内声明友元即可  
>  全局函数类外实现,需要告诉编译器类以及友元函数的实现,写在最上方
> 
> 
> 


代码讲解:



//全局函数设置在类外时需要做的工作
template<class T1, class T2>
class Student;
template<class T1, class T2>
void showInfo1(Student<T1, T2>p)
{
cout << “姓名:” << p.name << " 年龄:" << p.age << endl;
}
//类模板Student
template<class T1, class T2>
class Student
{

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

图片转存中…(img-Z3yOUqEW-1714494360762)]
[外链图片转存中…(img-3FQRfca6-1714494360763)]
[外链图片转存中…(img-tfU8O91Q-1714494360763)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值