既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
✨目录
类模板
建立一个通用类,类中的成员数据类型可以不具体确定,先用一个虚拟的类型来代表
语法:
template
创建类
示例:
template<class T1,class T2>
class Person
{
public:
T1 name;
T2 age;
};
先使用template关键字声明类模板,接着创建Person类,属性name和age用虚拟类型T1和T2声明,这就是最简单的类模板定义。
类模板与函数模板的区别
区别一:类模板没有自动类型推导方式
区别二:类模板在模板参数列表中可以有默认参数
注意事项:有默认参数的条件是参数列表的末尾需要指定数据类型;
由于没有自动类型推导方式,所以使用的时候不能省略**<>**
示例:
template<class T1, class T2=int>
class Person
{
public:
T1 name;
T2 age;
Person(T1 name, T2 age)
{
this->age = age;
this->name = name;
}
void showInfo()
{
cout << "姓名:" << name << " 年龄:" << age << endl;
}
};
void test02()
{
//Person p("叶落秋白", 18);报错,缺少对应的参数列表
Person<string,int>p1("叶落秋白", 18);
Person<string>p2("叶落秋白", 18);
p.showInfo();
}
可以看到第一行代码T2的后面指定了类型为整型,所以创建类模板对象的时候可以省略T2数据类型的指定,但是切记 :在不给参数列表最后一个虚拟类型指定数据类型的情况下是无法做到参数列表含有默认参数的。
类模板中的成员函数创建时机
类模板中的成员函数并不是一开始就创建的,只有在调用的时候才会被调用。这个知识点在下面的内容的理解上占据着重要作用。
代码测试:
class A
{
public:
void showInfo()
{
cout << "调用A类的成员函数" << endl;
}
};
class B
{
public:
void showInfo()
{
cout << "调用B类的成员函数" << endl;
}
};
template<class T>
class MyStudy
{
public:
T pre;
//类模板中的成员函数
void show()
{
pre.showInfo();
}
};
void test03()
{
MyStudy<A>* S = new MyStudy<A>();//创建A类属性的类模板对象S
MyStudy<B>* D = new MyStudy<B>();//创建B类属性的类模板对象D
S->show();
D->show();
delete S;//释放堆区指针
delete D;
S = NULL;
D = NULL;
}
由于成员属性pre的类型未指定是A类还是B类,所以编译器并不会创建成员函数,无法识别showInfo函数是哪一个类的成员函数。只有我们创建的时候给类模板对象指针指定T类型,这时候调用show方法编译器才会创建成员函数,实现对应的功能。
运行效果:
类模板对象做函数参数
三个形式:
指定传入类型
参数模板化
整个类模板化
代码演示:
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<class t>
void printInfo2(t & p)
{
p.showInfo();
cout << "t的类型为:" << typeid(t).name() << endl;
}
void test04()
{
Per<string> p("叶落秋白", 183);
printInfo(p);
}
void test4()
{
Per<string> p("微凉秋意", 184);
printInfo1(p);
}
void test4a()
{
Per<string>p("落叶归根",185);
printInfo2(p);
}
小结:第一种指定传入类型的方式最为常用,查看自动推导类型可以调用typeid(虚拟类型).name()函数。其实string类型原名特别长,调用typeid函数的时候可以查看,另外也可以直接查看整个类模板化时虚拟类型t的数据类型。
运行效果:
类模板与继承
类模板的继承不同于普通类的继承。这是因为类模板的属性数据类型事先并未指定,所以子类无法分配内存空间。
要点:
直接继承会提示缺少基类类的参数列表,需要继承的时候在基类后面指定<数据类型>
如果想要灵活指定父类中的T数据类型,子类也要变成类模板
代码示例:
template<class T>
class Base
{
public:
Base()
{
cout << "此时父类T的数据类型是:" << typeid(T).name() << endl;
}
T m;
};
//class Son :public Base<int>//这里可以直接指定,不过为了灵活指定,将子类变为类模板
//子类变成类模板
template<class T1,class T2>
class Son :public Base<T2>
{
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函数来查看由子类指定的父类的虚拟数据类型的具体类型。
运行效果:
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
g-jKxv8M9v-1715428335800)]
[外链图片转存中…(img-4exiwrNc-1715428335800)]
[外链图片转存中…(img-GgrU5EHE-1715428335800)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新