类模板
一、什么是类模版
类模版就是用模版参数来定义类,类模版可以用来创建通用的数据类型和函数,从而实现代码的重用。
1、语法
template <class T>
class 类模版名
{
//类体
};
实例化时这样使用:
类模版名 <需要使用的类型名> 对象名;
MyClass<int> a;
下面是一个例子:
template<class T1, class T2>
class MyClass
{
public:
T1 _a; //通用类型成员变量。
T2 _b;
MyClass(){}
MyClass(T1 a, T2 b):_a(a), _b(b){}
//通用类型成员函数参数
//通用类型用于成员函数的返回值
T1 get1()
{
T1 a = 2; //用于成员函数内变量的定义。
return _a + a;
}
T2 getb()
{
T2 b = 1;
return _b + b;
}
};
int main()
{
MyClass <int, string> a;
return 0;
}
2、注意
-
在创建对象的时候,必须指定类型,否则无法创建对象。
MyClass a; // 错误,无法创建对象 -
使用类模版时,数据类型必须适应类模版中的代码。
//将main函数中的double改为string,调用getb(),会将a中的_b改为1,但是_b是string类型,无法赋值为int,所以会报错 int main() { MyClass <int, string> a; a.getb(); //此句错误:T2 b = 1; return 0; } -
类模版可以为通用参数指定缺省的数据类型(C11标准的函数模版也可以)。
想使用缺省类型,只指定一个类型是行不通的:
template<class T1, class T2> class MyClass{...}; int main() { MyClass <int> a; //只指定一个类型,错误 return 0; }我们可以在创建类模版的时候,为通用参数指定缺省的类型。
template<class T1, class T2 = int> class MyClass{...}; int main() { MyClass <int> a; //只指定一个类型,正确 return 0; } -
类的成员函数可以在类外实现。
注意:不能在类外部的类模版成员声明上指定默认的参数模版。template <class T1, class T2 = double> class MyClass { public: MyClass(){} MyClass(T1 a, T2 b):_a(a), _b(b){} T1 _a; T2 _b; T1 geta(); T2 getb(); }; template <class T1, class T2> //错误情况:template<class T1, class T2 = double> T1 MyClass<T1, T2>::geta() { return _a; } //错误情况:template<class T1, class T2 = double> template <class T1, class T2> T2 MyClass<T1, T2>::getb() { return _b; } int main() { MyClass<int> a(10,3.14); a.getb(); return 0; } -
可以用new创建模版对象。
//使用默认构造函数 MyClass<int, double> *a = new MyClass<int, double>(); //指定参数 MyClass<int, double> *b = new MyClass<int, double>(10, 3.14); -
在程序中,模版类的成员函数使用了才会创建。
虽然创建了类的指针,但是没有创建类的对象,所以不会调用构造函数,模版类的任何成员函数,只要程序中没有调用,就不会创建。template <class T1> class MyClass { public: MyClass(){_a.abcbahsj();} MyClass(T1 a):_a(a){_a.abcbahsj();} T1 _a; }; int main() { MyClass<int> *a; //创建指针,但是没有创建对象,所以不会调用构造函数 return 0; }
二、类模版应用:栈
下面用C++实现一个顺序栈:
#include<iostream>
using namespace std;
class Stack
{
public:
//构造函数,初始化栈,并将top改为-1
Stack(){}
Stack(int size) : _Size(size), _top(-1)
{
_data = new int[_Size];
}
~Stack()
{
delete[] _data; //释放数组应该加上[]
_data = nullptr; // 虽然在这里设置nullptr是多余的,但有助于表明资源已被释放
}
void Push(int num)
{
if(!Full())
{ _top++;
_data[_top] = num;
}
}
void Pop(int &num)
{
if(!Empty())
{
num = _data[_top];
_top--;
}
}
void Print()
{
int temp = _top + 1;
for(int i = 0; i < temp; i++)
{
cout << _data[i] << endl;
}
}
bool Empty()
{
if(_top == -1)
{
return true;
}
return false;
}
bool Full()
{
if(_top == _Size - 1)
{
return true;
}
return false;
}
private:
int *_data; //连续空间存放数据
int _Size; //有多少元素
int _top; //栈顶指针
};
int main()
{
Stack s(10);
s.Push(10);
s.Push(20);
int num = 0;
s.Pop(num);
s.Print();
}
引入类模版,在初始化对象的时候需要指明类模版的数据类型。
template <class T>
class Stack
{
public:
void Push(T num)
{
if(!Full())
{ _top++;
_data[_top] = num;
}
}
void Pop(T &num)
{
if(!Empty())
{
num = _data[_top];
_top--;
}
}
private:
T *_data; //连续空间存放数据
};
int main()
{
//使用模版类的时候要指明数据类型
Stack<int> s(10);
}
三、类模版应用:数组
1、数组
#include<iostream>
using namespace std;
const int MAX_SIZE = 10;
class Array
{
public:
Array(){}
Array(int size): _status_size(0)
{
_data = new int[MAX_SIZE];
}
~Array()
{
delete[] _data;
_data = nullptr;
}
//插入
bool Insert(int pos, int num)
{
if (pos < 1 || pos > _status_size + 1 || IsFull()) return false;
for(int i = _status_size; i >= pos; i--)
{
_data[i] = _data[i - 1];
}
_data[pos - 1] = num;
_status_size++;
return true;
}
//删除
bool Delete(int pos)
{
if(pos < 1 || pos > _status_size) return false;
if(IsEmpty()) return false;
for(int i = pos; i < _status_size; i++)
{
_data[i - 1] = _data[i];
}
_status_size--;
return true;
}
//更改
int &operator[](int i)
{
return _data[i];
}
//访问
const int &operator[](int i) const
{
return _data[i];
}
//查询
int Search(int pos)
{
if(pos < 1 || pos > _status_size) return false;
return _data[pos - 1];
}
//判满
bool IsFull()
{
if(_status_size == MAX_SIZE)
{
return true;
}
return false;
}
//判空
bool IsEmpty()
{
if(_status_size == 0) return true;
return false;
}
//显式
void Show()
{
for(int i = 0; i < _status_size; i++)
{
cout << _data[i] << endl;
}
}
//扩容
public:
int *_data;
int _status_size; //
};
int main()
{
Array a(10);
a.Insert(1,10);
a.Insert(1,20);
a.Insert(1,30);
a.Insert(1,40);
a.Show();
cout << "a[2] = " << a[2] << endl;
return 0;
}
可以在类模版中加入数组大小,就不用再定义一个常量了。
#include<iostream>
using namespace std;
const int MAX_SIZE = 10;
template <class T, int len = 10>
class Array
{
public:
Array(){}
Array(int size): _status_size(0)
{
_data = new T[len];
}
~Array()
{
delete[] _data;
_data = nullptr;
}
//插入
bool Insert(int pos, T num)
{
if (pos < 1 || pos > _status_size + 1 || IsFull()) return false;
for(int i = _status_size; i >= pos; i--)
{
_data[i] = _data[i - 1];
}
_data[pos - 1] = num;
_status_size++;
return true;
}
//删除
bool Delete(int pos)
{
if(pos < 1 || pos > _status_size) return false;
if(IsEmpty()) return false;
for(int i = pos; i < _status_size; i++)
{
_data[i - 1] = _data[i];
}
_status_size--;
return true;
}
//更改
T &operator[](int i)
{
return _data[i];
}
//访问
const T &operator[](int i) const
{
return _data[i];
}
//查询
T Search(int pos)
{
if(pos < 1 || pos > _status_size) return false;
return _data[pos - 1];
}
//判满
bool IsFull()
{
if(_status_size == len)
{
return true;
}
return false;
}
//判空
bool IsEmpty()
{
if(_status_size == 0) return true;
return false;
}
//显式
void Show()
{
for(int i = 0; i < _status_size; i++)
{
cout << _data[i] << endl;
}
}
//扩容
public:
T *_data;
int _status_size;
};
int main()
{
Array<char> a(10); //使用缺省的数组大小
a.Insert(1,'a');
a.Insert(1,'b');
a.Insert(1,'c');
a.Insert(1,'d');
a.Show();
cout << "a[2] = " << a[2] << endl;
return 0;
}
2、类模版非通用类型参数规则
类模版可以有非通用类型参数,规则如下:
- 通常是整型(C++20可以使用其他)
- 实例化模版时必须使用常量表达式
- 模版中不能修改参数的值
#include <iostream>
#include <cstddef> // for size_t
// 1) 类模板定义,其中T是类型参数,N是非类型参数
//(在C++20之前,N通常是整型;C++20开始,可以使用其他类型,但整型仍最常见)
template <typename T, size_t N>
class MyArray
{
private:
T array[N]; // 使用非类型参数N来定义数组的大小
public:
MyArray()
{
for (size_t i = 0; i < N; ++i)
{
array[i] = T(); // 将每个元素初始化为其类型的默认值
}
}
void print() const
{
for (size_t i = 0; i < N; ++i)
{
std::cout << array[i] << " ";
}
std::cout << std::endl;
}
// 3) 在模板内部,不能修改非类型参数N的值
// 下面的方法是错误的示例,用于说明不能修改非类型模板参数
// void resize(size_t newSize)
{
// N = newSize; // 错误:在模板内部不能修改非类型参数N的值
// }
};
int main()
{
// 2) 实例化模板时,非类型参数N必须使用常量表达式
// 这里,5是一个常量表达式,因此可以用于实例化MyArray模板
MyArray<int, 5> myArray;
myArray.print();
// 注意:在myArray对象内部,我们不能修改N的值
// 例如,下面的代码是错误的,因为它试图修改一个编译时常量
// myArray.resize(10);
return 0;
}
四、模版的嵌套和递归
创建一个Vector缺省大小为2,Stack为3
创建一个Vector,容器的元素使用Stack
#include<iostream>
using namespace std;
template <class T>
class Vector
{
private:
int len;
T *_data;
public:
Vector(int size = 10) : len(size)
{
_data = new T[len];
}
~Vector()
{
delete[]_data;
_data = nullptr;
}
//扩展内存空间
void resize(int size = 2)
{
if(size <= len) return;
T* tmp = new T[size];
for(int i = 0; i < len; i++)
{
tmp[i] = _data[i];
//此处浅拷贝,复制的是类,类中使用堆区内存,就不对
}
delete [] _data;
_data = tmp;
len = size;
}
int size() const
{
return len;
}
T &operator[](int i)
{
if(i >= len)
{
resize(i + 10);
}
return _data[i];
}
const T& operator[](int i) const
{
return _data[i];
}
};
template <class T>
class Stack
{
public:
//构造函数,初始化栈,并将top改为-1
Stack() : _Size(3), _top(-1)
{
_data = new T[_Size];
}
Stack(int size) : _Size(size), _top(-1)
{
_data = new T[_Size];
}
~Stack()
{
delete[] _data; //释放数组应该加上[]
_data = nullptr; // 虽然在这里设置nullptr是多余的,但有助于表明资源已被释放
}
void Push(T num)
{
if (!Full())
{
_data[++_top] = num; // 先增加 _top,然后赋值
}
else
{
// 可以选择抛出异常、记录错误、或者动态调整栈大小
throw std::overflow_error("Stack is full");
}
}
void Pop(T &num)
{
if(!Empty())
{
num = _data[_top];
_top--;
}
}
void Print()
{
int temp = _top + 1;
for(int i = 0; i < temp; i++)
{
cout << _data[i] << endl;
}
}
bool Empty()
{
if(_top == -1)
{
return true;
}
return false;
}
bool Full()
{
if(_top == _Size - 1)
{
return true;
}
return false;
}
Stack& operator=(const Stack& s) //深拷贝
{
delete[] _data; //释放原内存
_Size = s._Size;
_data = new T[_Size]; //分配新内存
for(int i = 0; i < _Size; i++)
{
_data[i] = s._data[i];
}
_top = s._top;
return *this;
}
private:
T *_data; //连续空间存放数据
int _Size; //有多少元素
int _top; //栈顶指针
};
int main()
{
//创建一个Vector缺省大小为2,Stack为3
//创建一个Vector,容器的元素使用Stack
Vector<Stack<string>> v; //相当于创建了一个数组,数组中的每个元素都是一个栈
Stack<string> v1[2];
string v2[2][3];
//1)
//Vector<Stack<string>> v;
//这行代码声明了一个名为 v 的变量,它是 Vector 的一个实例,
//而 Vector 存储的元素类型是 Stack<string>。
//这里 Stack<string> 表示一个栈,栈中的元素是字符串类型(string)。
//在C++11之前,当使用两个连续的尖括号(>>)时,
//需要在它们之间添加一个空格以避免解析错误,
//因为编译器可能会将 >> 误解为右移操作符。从C++11开始,这个空格不是必需的。
//2)
//Stack<string> v1[2];
//这行代码声明了一个名为 v1 的数组,数组中有两个元素,
//每个元素都是 Stack<string> 类型。
//这意味着 v1 是一个包含两个栈的数组,每个栈都可以存储字符串。
//3)
//string v2[2][3];
//这行代码声明了一个名为 v2 的二维数组,
//数组的大小是 2x3,即两行三列,数组中的元素类型是 string。
//这意味着 v2 可以存储 6 个字符串,排列成两行三列的形式。
//手工插入数据
v[0];
v[0].Push("小1");
v[0].Push("小2");
v[0].Push("小3"); //v容器中的第0个栈
v[1]; v[1].Push("小1"); v[1].Push("小2"); v[1].Push("小3"); //v容器中的第1个栈
v[2].Push("哈哈哈"); v[2].Push("棒棒");
//如何将这个嵌套容器全部显式呢?用嵌套循环
for(int i = 0; i < v.size(); i++) //遍历Vector容器
{
while(v[i].Empty() == false) //栈不为空栈
{
string temp;
v[i].Pop(temp);
cout << "data = " << temp << endl;
}
}
}
五、类模版的具体化
类模版的具体化有两种:
完全具体化和部分具体化
具体化程度高的类 > 具体化程度低的类
具体化的类 > 没有具体化的类。
#include<iostream>
using namespace std;
//没有具体化的类
template<class T1, class T2>
class A
{
public:
T1 _x;
T2 _y;
A(const T1 x, const T2 y):_x(x),_y(y)
{
cout << "类模板:构造函数\n" << endl;
}
void show() const;
};
template<class T1, class T2>
void A<T1, T2>::show() const
{
cout << "类模板 x = " << _x << " y = " << _y << endl;
}
模板函数完全具体化
template<>
class A<int , string>
{
public:
int _x;
string _y;
A(const int x, const string y): _x(x), _y(y)
{
cout << "完全具体化:构造函数" << endl;
}
void show()const;
};
void A<int , string>::show() const
{
cout << "完全具体化 x = " << _x << " y = " << _y << endl;
}
//类模板部分显示具体化
template<class T1>
class A<T1, string>
{
public:
T1 _x;
string _y;
A(const T1 x, const string y):_x(x), _y(y)
{
cout << "部分具体化:构造函数" << endl;
}
void show()const;
};
template <class T1>
void A<T1, string>::show() const
{
cout << "部分具体化 x = " << _x << " y = " << _y << endl;
}
int main()
{
A<int ,string> a(8, "hhh"); //完全具体化的版本
a.show();
//接着注释掉完全具体化的版本,在此构造
A<int ,string> b(8, "hhh"); //部分具体化的版本
b.show();
//接着注释掉部分具体化的版本
A<int ,string> c(8, "hhh");
c.show(); //没有具体化的版本
}
六、模板类与继承
- 模板类继承普通类,在派生类中指明基类的构造函数即可。
此时会报错,显示A没有默认的构造函数,需要我们在派生类的构造函数的初始化列表中指明基类的构造函数。#include<iostream> using namespace std; class A { public: int _a; A(int a) : _a(a) { cout << "调用了A的构造函数" << endl; } void func1() { cout << "调用了func1()函数" << endl; } }; template <class T1, class T2> class B: public A { public: T1 _x; T2 _y; B(const T1 x, const T2 y): _x(x), _y(y) { cout << "调用了B的构造函数" << endl; } void func2() { cout << "调用了func2()函数 x = " << _x << " y = " << _y << endl; } }; int main() { B<int, int> b(10, 20); b.func2(); return 0; }B(const T1 x, const T2 y, int a): A(a), _x(x), _y(y) - 普通类继承模板类的实例版本,需要在派生类中指定基类的实例版本,并且在派生类的构造函数中指明基类的构造函数。
template <class T1, class T2> class B { public: T1 _x; T2 _y; B(const T1 x, const T2 y): _x(x), _y(y) { cout << "调用了B的构造函数" << endl; } void func2() { cout << "调用了func2()函数 x = " << _x << " y = " << _y << endl; } }; class A: public B<int, int> { public: int _a; A(int a, int x, int y) :B(x, y) , _a(a) { cout << "调用了A的构造函数" << endl; } void func1() { cout << "调用了func1()函数" << endl; } }; int main() { A a(10, 20 ,30); a.func1(); return 0; } - 普通类继承模板类。
template <class T1, class T2> class B { public: T1 _x; T2 _y; B(const T1 x, const T2 y): _x(x), _y(y) { cout << "调用了B的构造函数" << endl; } void func2() { cout << "调用了func2()函数 x = " << _x << " y = " << _y << endl; } }; template <class T1, class T2> class A: public B<T1, T2> { public: int _a; A(int a, const T1 x, const T2 y) :B<T1, T2>(x, y) , _a(a) { cout << "调用了A的构造函数" << endl; } void func1() { cout << "调用了func1()函数" << endl; } }; int main() { A<int, int> a(10, 20 ,30); a.func1(); return 0; } - 模板类继承模板类
template <class T1, class T2> class B { public: T1 _x; T2 _y; B(const T1 x, const T2 y): _x(x), _y(y) { cout << "调用了B的构造函数" << endl; } void func2() { cout << "调用了func2()函数 x = " << _x << " y = " << _y << endl; } }; template <class T, class T1, class T2> class C:public B<T1, T2> { public: T _a; C(){} C(const T a, const T1 b, const T2 c): B<T1, T2>(10, 20), _a(a) { cout << "调用了C的构造函数" << endl; } void func3() { cout << "调用了func3()函数" << endl; } }; int main() { C<int, int, int> c(10, 20, 30); return 0; } - 模板类继承模板参数给出的基类(不能是模板类)
#include<iostream> using namespace std; class A { public: A() { cout << "调用了A()" << endl; } A(int a) { cout << "调用了A(int a)" << endl; } }; class B { public: B() { cout << "调用了B()" << endl; } B(int b) { cout << "调用了B(int b)" << endl; } }; class C { public: C() { cout << "调用了C()" << endl; } C(int c) { cout << "调用了C(int c)" << endl; } }; template<class T> //D是模板类 class D { public: D(){cout << "调用了D的构造函数D()" << endl;} D(int a) {cout << "调用了D的构造函数D(int a)" << endl;} }; template<class T> class E :public T //模板类继承模板参数给出的基类 { public: E():T() { cout << "调用了E的构造函数" << endl; } E(int a):T(a) { cout << "调用了E的构造函数E(int a)" << endl; } }; int main() { E<A> ea1; //A作为基类 E<B> eb1; //B作为基类 E<C> ec1; //C作为基类 //E<D<int>> ed1; //D<int>作为基类 E<D> ed1; //报错,DD不能直接作为基类 return 0; }
七、模板类和函数
模板类可以用于函数的参数和返回值。
-
普通函数,参数和返回值是模板类的实例化版本。
template <class T1, class T2> class A { public: A(const T1 x, const T2 y):_x(x), _y(y){} T1 _x; T2 _y; void show() const { cout << "show() x = " << _x <<" y = " << _y << endl; } }; //采用普通函数,参数和返回值是模板类的实例化版本。 A<int, string> func(A<int, string> &a) { a.show(); cout << "调用了func(A<int, string> &a" << endl; return a; } int main() { A<int, string> a(3, "aaa"); func(a); //参数是模板类的实例化版本 }如果将main函数中的int和string换成其他类型,会报错。
A<double, char> a(3.14, 'a'); //报错需要将普通函数func()转换为函数模板。
-
函数模板,参数和返回值是某种的模板类。
//函数模板,参数和返回值是模板类A template<typename T1, typename T2> A<T1, T2> func(A<T1, T2> &a) { a.show(); cout << "调用了func(A<T1, T2> &a)" << endl; return a; } int main() { A<char, int> a('r', 100); func(a); }注意:如果普通函数和函数模板同时存在,优先调用普通函数。
-
函数模板,参数和返回值是任意类型(支持普通类和模板类和其他类型)。
class B { public: void show(){cout << "调用了B的show()方法" << endl;} }; //函数模板,参数和返回值是任意类型 template <typename T> T func(T &t) { t.show(); cout << "调用了func(T &t)" << endl; return t; } int main() { B b; func(b); return 0; }参数是仿函数:
class B { public: void operator()() //重载了()运算符(仿函数) { cout << "调用了BB类的仿函数" << endl; } }; //函数模板,参数和返回值是任意类型 template <typename T> T func(T t) { t(); } int main() { B b; func(b); return 0; }参数是函数指针
void show() { cout << "调用了show()函数" << endl; } //函数模板,参数和返回值是任意类型 template <typename T> T func(T t) { t(); } int main() { func(show); return 0; }
八、模板类与友元
-
非模版友元:友元函数不是模版函数,而是利用模版类参数生成的函数。
template<class T1, class T2> class A { private: T1 _x; T2 _y; public: A(const T1 x, const T2 y): _x(x), _y(y){} //此处这个show()并非函数模版,而是用模版类参数生成的函数。因为下面具体化的函数不能和他并存,并且只能在这个类中使用。 //两个show()并存会报错 friend void show(A<T1, T2>& a) { cout << "_x = " << a._x << " _y = " << a._y << endl; } friend void show(A<int, string> &a); }; void show(A<int, string> &a) { cout << "_x = " << a._x << " _y = " << a._y << endl; } int main() { A<int, int> a(10, 20); show(a); A<int, string> b(10,"hhhh"); return 0; } -
约束模版友元:模版类实例化时,每个实例化的类对应一个友元函数。
#include<iostream> using namespace std; //约束模版友元:模版类实例化时,每个实例化的类对应一个友元函数 template <typename T> void show(T &a); //第一步:在模版类的前面,声明友元函数模版,让类知道 template<class T1, class T2> class A { private: T1 _x; T2 _y; friend void show<>(A<T1, T2> &a); //第二部:在模版类中,再次声明友元函数模版,让编译器知道 //编译器在实例化某种数据类型的模版类时,也会实例化这种数据类型的模版函数 public: A(const T1 x, const T2 y):_x(x), _y(y){} }; template <typename T> //第三部:定义友元函数模版,可以与具体化函数共存 void show(T &a) { cout << "通用:x = " << a._x << " y = " << a._y << endl; } template<> void show(A<int, string> &a) { cout << "具体化A<int, string>: x = " << a._x << " y = " << a._y << endl; } int main() { A<int, string> a(10, "hhh"); show(a); //调用具体化版本 //show(a); //注释掉具体化的show函数后,调用通用版本 return 0; }
这种友元的函数模版可以用于多个模版类。
//第一步:在模版类的前面,声明友元函数模版,让类知道
template <typename T>
void show(T &a);
template<class T1, class T2>
class A
{
private:
T1 _x;
T2 _y;
//第二步:在模版类中,再次声明友元函数模版,让编译器知道
//编译器在实例化某种数据类型的模版类时,也会实例化这种数据类型的模版函数
friend void show<>(A<T1, T2> &a);
public:
A(const T1 x, const T2 y):_x(x), _y(y){}
};
template<class T1, class T2>
class B
{
private:
T1 _x;
T2 _y;
friend void show<>(B<T1, T2> &b);
public:
B(const T1 x, const T2 y):_x(x), _y(y){}
};
//第三步:定义友元函数模版,可以与具体化函数共存
template <typename T>
void show(T &t)
{
cout << "通用:x = " << t._x << " y = " << t._y << endl;
}
int main()
{
A<char, string> a('a',"hhhhh");
show(a);
B<string, string> b("nihao", "hi");
show(b);
return 0;
}
-
非约束模版友元(实际开发中不用):模版类实例化时,如果实例化了n个类,也会实例化n个友元函数,每个实例化的类都拥有n个友元函数。
#include<iostream> using namespace std; //非类模版约束的友元函数,实例化后,每个函数都是每个类的友元 template<class T1, class T2> class A { private: template<typename T> friend void show(T &a); //函数模版show成为A的友元函数 T1 _x; T2 _y; public: A(const T1 x, const T2 y):_x(x), _y(y){} }; template<typename T> void show(T &a) //通用的函数模版 { cout << "通用 x = " << a._x << " y = " << a._y << endl; } template<> void show(A<int, string> &a) //函数模版的具体化 { cout << "具体化 x = " << a._x << " y = " << a._y << endl; } int main() { A<int, string> a(10, "hhh"); //调用具体化版本 show(a); A<char, int> b('a', 10000); //调用通用版本 show(b); return 0; }
九、类模版的成员模版
类模版中可以定义成员模版,成员模版也可以是函数模版,也可以是类模版。
#include <iostream>
using namespace std;
template<class T1, class T2>
class A
{
public:
T1 _x;
T2 _y;
A(const T1 x, const T2 y):_x(x), _y(y){}
void show()
{
cout << "x = " << _x << " y = " << _y << endl;
}
template <class T>
class B
{
public:
T _a;
T1 _b;
B(){}
void show()
{
cout << "_a = " << _a << " _b = " << _b << endl;
}
};
B<string> b;
template<typename T>
void show(T t) //与show参数不同,可以重载
{
cout << "t = " << t << endl;
cout << "_x = " << _x << " _y = " << _y << endl;
b.show();
}
};
int main()
{
A<int, string> a(10, "hhh");
a.show(10);
}
类成员的成员模版,定义也可以放到类的外面
... //前面不做改动
template <class T>
class B
{
public:
T _a;
T1 _b;
B(){}
void show(); //此处仅声明
};
template<class T1, class T2> //放A的模版参数
template <class T> //放B的模版参数
void A<T1, T2>::B<T>::show() //此处定义
{
cout << _a << " " << _b << endl;
}

浙公网安备 33010602011771号