//C++ Generic Programming – Chapter 3 – Class Templates – 3.2 Class Template Definition
// C++ 泛型编程 -第三章 -类模版- 3.2 – 类模板定义
#include <iostream>
using namespace std;
//上节课已经实现了动态数组类 但是遗留了一个类型是整型的类冗余问题
//只需要建立类模板 减少冗余问题
/*
class DynamicArray
{
private:
int* elements;
int size;
public:
DynamicArray(int n) : size(n)
{
elements = new int[size];
}
~DynamicArray()
{
delete[] elements;
}
int& operator[](int index)
{
return elements[index];
}
};
*/
template<class T>//可以写typename 也可以写class(这里的class跟下面的不是同一个意思) T是动态数组元素的虚拟类型
class DynamicArray
{
private:
T* elements;//这里的int改成T
//剩下的代表大小 索引的int不用改
int size;
public:
DynamicArray(int n) : size(n)
{
elements = new T[size];//在申请内存的时候 这里的int也改成T
}
~DynamicArray()
{
delete[] elements;
}
T& operator[](int index)//在返回元素值时这里的int也改成T
{
return elements[index];
}
};
int main()
{
//int n = 10;
//int* p = new int[n];
//DynamicArray da(100);//在类模板实例化时我需要指定一个类型
DynamicArray<double>da(100);
da[1] = 3.1;
da[9] = 4.2;
cout << da[0] << ‘ ‘ << da[1] << endl;
DynamicArray<char>dac(10);
dac[0] = ‘A’;
dac[1] = ‘C’;
dac[2] = ‘M’;
cout << dac[0] << dac[1] << dac[2] << endl;
//类模板的定义和使用 好处:可以让代码进行复用 避免为不同的数据类型编写重复代码 提高了程序的通用性和灵活性
return 0;
}
//C++ Generic Programming – Chapter 3 – Class Templates – 3.3 Member Function – 3.3.1 In – Class Definition
//C++ 泛型编程 -第三章 -类模版- 3.3 – 成员函数 3.3.1 类内定义
#include <iostream>
using namespace std;
//类模板的成员函数在类内的定义
template<class T>//可以写typename 也可以写class(这里的class跟下面的不是同一个意思) T是动态数组元素的虚拟类型
class DynamicArray
{
private:
T* elements;//这里的int改成T
//剩下的代表大小 索引的int不用改
int size;
public:
DynamicArray(int n) : size(n)
{
elements = new T[size];//在申请内存的时候 这里的int也改成T
}
~DynamicArray()
{
delete[] elements;
}
T& operator[](int index)//在返回元素值时这里的int也改成T 这里T是返回值
//这就是成员函数了 和普通成员函数没有什么很大的区别 只需要把需要替换的类型替换成虚拟类型就可以了
{//和我们之前学过的函数模板很像 甚至除了定义位置以外 其他都是一模一样的 这个模板的定义在外面 成员函数函数的定义是在类里面
return elements[index];
}
//类模板的成员函数的实现 其他实现都和普通类一模一样 只不过在涉及到这个虚拟类型有关的传参或者返回值的时候 需要替换成我们定义的虚拟类
//
//更新第 index个索引的元素,把它的值改成 value
//int
void update(int index, T value) {//这里T是传参 不要把T写成int 写成int后编译器不会报错 但是逻辑本身也是错的
elements[index] = value; //如果把int写成T 会触发强制类型转换
//想办法把这些类内定义的函数抽到类外去定义
}
};
int main()
{
DynamicArray<char> dac(100);
dac[56] = ‘h’;
cout << dac[56] << endl;
dac.update(56, ‘u’);
cout << dac[56] << endl;
return 0;
}
//C++ Generic Programming – Chapter 3 – Class Templates – 3.3 Member Function – 3.3.2 Out-of-Class Definition
v
#include <iostream>
using namespace std;
//类模板的成员函数在类内的定义
template<class T>//可以写typename 也可以写class(这里的class跟下面的不是同一个意思) T是动态数组元素的虚拟类型
class DynamicArray
{
private:
T* elements;//这里的int改成T
//剩下的代表大小 索引的int不用改
int size;
public:
//把成员函数放到类外实现
// 实现删掉
//1、保留声明
DynamicArray(int n); /* : size(n)
{
elements = new T[size];//在申请内存的时候 这里的int也改成T
}*/
//析构函数也按步骤实现一下
~DynamicArray();/*
{
delete[] elements;
}*/
T& operator[](int index);//在返回元素值时这里的int也改成T 这里T是返回值
//这就是成员函数了 和普通成员函数没有什么很大的区别 只需要把需要替换的类型替换成虚拟类型就可以了
//{//和我们之前学过的函数模板很像 甚至除了定义位置以外 其他都是一模一样的 这个模板的定义在外面 成员函数函数的定义是在类里面
// return elements[index];
// }//这里不注释也可以 搬到类外
//类模板的成员函数的实现 其他实现都和普通类一模一样 只不过在涉及到这个虚拟类型有关的传参或者返回值的时候 需要替换成我们定义的虚拟类
//
//更新第 index个索引的元素,把它的值改成 value
//int
void update(int index, T value); /* {//这里T是传参 不要把T写成int 写成int后编译器不会报错 但是逻辑本身也是错的
elements[index] = value; //如果把int写成T 会触发强制类型转换
//想办法把这些类内定义的函数抽到类外去定义
}*/
//这样就只剩下成员函数的定义和成员函数的声明了 很干净 具体函数的实现就到类外面去了
};
//2、拷贝声明
//3、加作用域
//4、拷贝实现
//5、模板参数列表声明
//6、指定虚拟类型
template<class T>
DynamicArray<T>::DynamicArray(int n) : size(n)//加上作用域 类名和两个冒号 并把之前的部分拷贝过来
{
elements = new T[n];//在申请内存的时候 这里的int也改成T
}
template<class T>
DynamicArray<T>::~DynamicArray() {
delete[] elements;
}
template<class T>
T& DynamicArray<T>::operator[](int index) {//规定 这个作用域要加在 函数名和返回值之间
return elements[index];
}
template<class T>
void DynamicArray<T>::update(int index, T value) {
elements[index] = value;
}
int main()
{
DynamicArray<char> dac(100);
dac[56] = ‘h’;
cout << dac[56] << endl;
dac.update(56, ‘u’);
cout << dac[56] << endl;
return 0;
}
//C++ Generic Programming – Chapter 3 – Class Templates – 3.3 Member Function – 3.3.3 Creation Timing
//C++ 泛型编程 -第三章 -类模版- 3.3 – 成员函数 3.3.3 创建时机
//类模板中成员函数的创建时机
#include <iostream>
using namespace std;
//对于普通类中的成员函数 在一开始时就已经创建出来了
//类模板的成员函数 会在调用时才会去创建
class Player {
public:
void run() {
cout << “跑步” << endl;
}
};
class Ball {
public:
void drop() {
cout << “下落” << endl;
}
};
template<class T>
class Test {
T obj; //编译不出错 说明对于编译器来讲 obj是啥都不知道
public:
void move1() { //所以这两个函数在一开始时根本没有创建出来
obj.run();
}
void move2() {//所以这两个函数在一开始时根本没有创建出来
obj.drop();
}
};
int main() {
Test<Player> test1;
test1.move1();
//test1.move2();//error C2039: ‘drop’: is not a member of ‘Player’
Test<Ball> test2;
//test2.move1();//它是Ball Ball没有run 只有drop
test2.move2();
//这也就验证了 这个类模板的成员函数 当我没有调用它之前 实际上并没有生成出来 这就是类模板成员函数的创建时机
return 0;
}
//C++ Generic Programming – Chapter 3 – Class Templates – 3.4 Parameter Passing for Object Functions
//C++ 泛型编程 -第三章 -类模版-3.4 对象的函数传参
#include <iostream>
using namespace std;
//当类模板实例化出来的对象作为函数参数时如何进行传递
template<class NameType, class HpType>//两个虚拟类型需要加上声明
class Hero {
public:
Hero(NameType name, HpType hp) {//写一个构造函数 传两个变量进来 类型是NameType和HpType
this->m_name = name; //赋值
this->m_hp = hp;
}
private:
NameType m_name;//虚拟类型1
HpType m_hp;//虚拟类型2
};
//1、直接指定类型
void test1(Hero<string, double>& h) { //加个引用 因为要拷贝一份新的 就是它本身
}
//2、参数模板化
template<typename T1, typename T2>
void test2(Hero<T1, T2>& h) { //加个引用 因为要拷贝一份新的 就是它本身
//把参数类型变成T1 跟T2
//然后因为是虚拟类型 所以要加上一个模板参数列表的声明 这就是我们之前学过的函数模板
}
//3、类模板化
template<typename T>//只有一个类了
void test3(T& h) { //加个引用 因为要拷贝一份新的 就是它本身
}
//三种方法都有应用场景 怎么使用看你实际的需要
int main() {
//函数里面通过类模板 实例化一个对象
Hero<string, double> h(“宋江”, 100.0);//这个Hero类有两个模板参数
test1(h);//函数的实际参就是这个h
test2(h);
test3(h);
return 0;
}
//C++ Generic Programming – Chapter 3 – Class Templates – 3.5 Class Template Inheritance
// C++ 泛型编程 – 第三章 – 类模版 – 3.5 类模板的继承
#include <iostream>
using namespace std;
//类模板的继承 一旦你写错了 编译器会直接告诉你 错的很明确
template<class NameType, class HpType>
class Hero {
public:
Hero(NameType name, HpType hp) {
this->m_name = name;
this->m_hp = hp;
}
private:
NameType m_name;
HpType m_hp;
};
//这个Hero类 它是个父类 并且是个类模板 那我现在需要写个子类去继承它
//class HeroSon : public Hero<string,double>{ //对于类模板来说 当我们实例化对象的时候 需要显示指定参数 继承也一样
//
//};
template<class T1,class T2,class T3>
class HeroSon : public Hero<T1, T2> { //子类想用的时候 我还是希望这两个参数进行模板化 所以需要用虚拟类型来替代掉
//HeroSon子类里可能需要有虚拟类型
T3 a;
//这节课也可以自己敲代码 通过编译器的指引把代码敲对
};
int main() {
return 0;
}