一.概念
类模版和函数模版的定义和使用类似,上篇博客已经介绍了函数模版,有时,有两个或者类,其功能是相同的,仅仅是数据类型不同,如下面语句声明了一个类
注意:1.类模版用于实现所需数据的类型参数化
2.类模版在表示如数组,表,图等数据结构显得提别重要
3.这些数据结构表示和算法不收所包含的元素类型的影响
二.单个类模版语法
看如下代码:
template <typename T>
class A
{
private:
T a;
public:
A(T a)
{
this->a = a;
}
void print()
{
cout << "a=" << a << endl;
}
};
void test(A<int> &n)//类模版做函数参数的用法
{
n.print();
}
int main()
{
//用模版类生成具体的类,用具体的类生成具体的对象
{
A<int> c1(10);
c1.print();
test(c1);
}
{
A<double> c1(99.9);
c1.print();
}
system("pause");
return 0;
}
三.继承中的类模版语法
1.从模版类派生一个普通类
template <typename T>
class A
{
protected:
T a;
public:
A(T a)
{
this->a = a;
}
void print()
{
cout << "a=" << a << endl;
}
};
//类模版派生时,需要具体化模版类,C++编译器需要知道父类的数据类型具体是什么样子的
//要知道父类所占的内存大小是多少,只有数据类型固定下来,否则不知道怎么分配内存
class B :public A<int>
{
private:
int b;
public:
B(int a, int b) :A<int>(a)
{
this->b = b;
}
void print1()
{
cout << "a=" << a << " b="<<b << endl;
}
};
int main()
{
B c1(10, 20);
c1.print1();
system("pause");
return 0;
}
2.从模版类派生模版类
template <typename T>
class A
{
protected:
T a;
public:
A(T a)
{
this->a = a;
}
void print()
{
cout << "a=" << a << endl;
}
};
template <typename T>
class B :public A<T>
{
private:
T b;
public:
B(T a b) :A<T>(a)
{
this->b = b;
}
void print()
{
cout << "b="<<b << endl;
}
};
int main()
{
B<int> c1(1, 2);
c1.print();
system("pause");
return 0;
}
四.类模版语法知识体系梳理
1.所有类模版函数写在类内部
template <typename T>
class complex
{
private:
friend ostream& operator<<(ostream &out, const complex &n)//写在类内部没有问题,等会写在类外部就会出问题。等会看下个代码
{
{
out << "a=" << n.a << " b=" << n.b << endl;
return out;
}
}
friend complex mysub(const complex &n, const complex&m)
{
complex c1(n.a - m.a, n.b - m.b);
return c1;
}
T a;
T b;
public:
complex(T a, T b)
{
this->a = a;
this->b = b;
}
void print()
{
cout << "a=" << a << " b=" << b << endl;
}
complex operator+(const complex &n)
{
complex c1(this->a + n.a, this->b + n.b);
return c1;
}
};
int main()
{
//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
complex <int>c1(1, 2);
complex<int> c2(2, 4);
complex<int> c3=c1 + c2;
cout << c1 + c2;
c3.print();
cout << mysub(c1, c2);
system("pause");
return 0;
}
2.所有模版函数都写在类的外部,不过都写在一个文件中,比如.cpp文件
template <typename T>
class complex
{
private:
friend ostream& operator<<(ostream &out, const complex &n)
{
out << "a=" << n.a << " b=" << n.b << endl;
return out;
}
friend complex mysub(const complex &n, const complex&m)
{
complex c1(n.a - m.a, n.b - m.b);
return c1;
}
T a;
T b;
public:
complex(T a, T b);
void print();
complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
this->a = a;
this->b = b;
}
template <typename T>
void complex<T>::print()
{
cout << "a=" << a << " b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
return c1;
}
int main()
{
//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
complex <int>c1(1, 2);
complex<int> c2(2, 4);
complex<int> c3=c1 + c2;
cout << c1 + c2;
c3.print();
system("pause");
return 0;
}
现在还没有将友元函数写在外面,代码没有任何问题,接下来将友元也写在外面
template <typename T>
class complex
{
private:
friend ostream& operator<<(ostream &out, const complex &n);
friend complex mysub(const complex &n, const complex&m)
{
complex c1(n.a - m.a, n.b - m.b);
return c1;
}
T a;
T b;
public:
complex(T a, T b);
void print();
complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
this->a = a;
this->b = b;
}
template <typename T>
void complex<T>::print()
{
cout << "a=" << a << " b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
return c1;
}
template <typename T>
ostream& operator<<(ostream &out, const complex<T> &n)
{
out << "a=" << n.a << " b=" << n.b << endl;
return out;
}
int main()
{
//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
complex <int>c1(1, 2);
complex<int> c2(2, 4);
complex<int> c3=c1 + c2;
cout << c1 + c2;
c3.print();
system("pause");
return 0;
}
程序一跑就出问题
这是为什么呢?
因为:和函数模版的机制有问题,因为两次编译生成的函数头不一样。
template <typename T>
class complex
{
private:
friend ostream& operator<<<T>(ostream &out, const complex<T> &n);
friend complex mysub(const complex &n, const complex&m)//此函数刚才忘记添加,自己加上即可
{
complex c1(n.a - m.a, n.b - m.b);
return c1;
}
T a;
T b;
public:
complex(T a, T b);
void print();
complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
this->a = a;
this->b = b;
}
template <typename T>
void complex<T>::print()
{
cout << "a=" << a << " b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
return c1;
}
template <typename T>
ostream& operator<<(ostream &out, const complex<T> &n)
{
out << "a=" << n.a << " b=" << n.b << endl;
return out;
}
int main()
{
//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
complex <int>c1(1, 2);
complex<int> c2(2, 4);
complex<int> c3=c1 + c2;
//c1 << cout;// complex <int>c1(1, 2);
operator<<(cout, c1);
c3.print();
system("pause");
return 0;
}
所以说不要滥用友元函数~一般情况下左移和右移运算符重载用友元函数,其余的尽量不要用不然就会出错,不然我们继续往下看
接下来我们将这个函数
friend complex mysub(const complex &n, const complex&m)
{
complex c1(n.a - m.a, n.b - m.b);
return c1;
}
弄到模版类外面,看看是什么样的
template <typename T>
class complex
{
private:
friend ostream& operator<<<T>(ostream &out, const complex<T> &n);
friend complex mysub(const complex &n, const complex&m);
T a;
T b;
public:
complex(T a, T b);
void print();
complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
this->a = a;
this->b = b;
}
template <typename T>
void complex<T>::print()
{
cout << "a=" << a << " b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
return c1;
}
template <typename T>
ostream& operator<<(ostream &out, const complex<T> &n)
{
out << "a=" << n.a << " b=" << n.b << endl;
return out;
}
template <typename T>
complex<T> mysub(const complex<T> &n, const complex<T>&m)
{
complex c1(n.a - m.a, n.b - m.b);
return c1;
}
int main()
{
//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
complex <int>c1(1, 2);
complex<int> c2(2, 4);
complex<int> c3=c1 + c2;
cout << mysub(c1,c2);
c3.print();
system("pause");
return 0;
}
一样会出错,怎么解决呢?
友元函数如果不是实现函数重载,写在类外,需要进行类的前置声明和函数的前置声明
如下:
代码如下:
template <typename T>
class complex;
template<typename T>
complex<T> mysub(const complex<T> &n, const complex<T>&m);
template <typename T>
class complex
{
private:
friend ostream& operator<<<T>(ostream &out, const complex<T> &n);
friend complex<T> mysub<T>(const complex<T> &n, const complex<T>&m);
T a;
T b;
public:
complex(T a, T b);
void print();
complex operator+(const complex &n);
};
template <typename T>
complex<T>::complex(T a, T b)
{
this->a = a;
this->b = b;
}
template <typename T>
void complex<T>::print()
{
cout << "a=" << a << " b=" << b;
}
template <typename T>
complex<T> complex<T>::operator+(const complex<T> &n)
{
complex c1(this->a + n.a, this->b + n.b);//在这个里面加不加<T>都可以
return c1;
}
template <typename T>
ostream& operator<<(ostream &out, const complex<T> &n)
{
out << "a=" << n.a << " b=" << n.b << endl;
return out;
}
template <typename T>
complex<T> mysub<T>(const complex<T> &n, const complex<T>&m)
{
complex<T> c1(n.a - m.a, n.b - m.b);
return c1;
}
int main()
{
//需要把模版类具体话以后才能定义对象,因为编译器要分配内存
complex <int>c1(1, 2);
complex<int> c2(2, 4);
complex<int> c3=c1 + c2;
cout << mysub(c1,c2);
c3.print();
system("pause");
return 0;
}
3.所有模版函数都写在类的外部,不过都写在.h;.cpp文件中
就是分文件写,这里就不多做介绍了。
总之一句话,不要乱用友元函数~
五.类模版中的static关键字
看如下代码:
template <typename T>
class A
{
public:
static T a;
};
template <typename T>
T A<T>::a = 0;
int main()
{
{
A<int> c1, c2, c3;
c1.a++;
c2.a++;
c3.a++;
cout << A<int>::a << endl;
}
{
A<char> c1, c2, c3;
c1.a = 'a';
c2.a++;
c3.a++;
cout << A<char>::a << endl;
}
system("pause");
return 0;
}
各自用自己static 变量~
以上就是类模版的基本用法!