C++类模板
在网上已经有很多相关概念了,
这里我说一下我的理解:
1、代码重点在于数据,数据就会就会有范围之分,这就联系到了地址。
2、不同的数据类型,占用的不同的地址空间是不同的。
3、执行相同逻辑的代码因为使用的数据类型不同,得到的结果有时候会差距很大。
4、基于以上三点,我认为模板概念就是划一片空间出来作为预备空间,在这片空间里面至少有8字节(long long在64位系统中是八字节),在这片空间里面可以随意变换类型也就是不同数据类型所申请的不同空间。
5、既然是地址空间,则我认为这就是一个类似于宏,来对地址进行申请,也就是关键字,template,
之后的 template 这里的typename T我认为方便理解就是一个设置好的define(不严谨)告诉计算机这是一个对应的模板变量T,不要报错哈。
6、基于上面描述我们可以知道个大概,之后我将举举几个例子这里的例子是借鉴:
https://www.jianshu.com/p/70ca94872418。
1 基础的类模板
类模板,可以定义相同的操作,拥有不同数据类型的成员属性。
通常使用template来声明。告诉编译器,碰到T不要报错,表示一种泛型.
如下,声明一个普通的类模板:
templateclass Complex{ public: //构造函数 Complex(T a, T b) { this->a = a; this->b = b; } //运算符重载 Complex operator+(Complex &c) { Complex tmp(this->a+c.a, this->b+c.b); return tmp; } private: T a; T b; } int main() { //对象的定义,必须声明模板类型,因为要分配内容 Complex a(10,20); Complex b(20,30); Complex c = a + b; return 0; }
2 模板类的继承
在模板类的继承中,需要注意以下两点:
如果父类自定义了构造函数,记得子类要使用构造函数列表来初始化
继承的时候,如果子类不是模板类,则必须指明当前的父类的类型,因为要分配内存空间
继承的时候,如果子类是模板类,要么指定父类的类型,要么用子类的泛型来指定父类
templateclass Parent{ public: Parent(T p) { this->p = p; } private: T p; }; //如果子类不是模板类,需要指明父类的具体类型 class ChildOne:public Parent { public: ChildOne(int a,int b):Parent(b) { this->cone = a; } private: int cone; }; //如果子类是模板类,可以用子类的泛型来表示父类 template class ChildTwo:public Parent { public: ChildTwo(T a, T b):Parent (b) { this->ctwo = a; } private: T ctwo; };
这里我们探讨一下friend在模板中的一些坑,
以下代码,运用的时候会报错
(我的IDE是vs2017)
#includeusing namespace std; template class Complex { //友元函数实现运算符重载 friend ostream& operator<<(ostream &out, Complex &c); public: Complex(T a, T b); //运算符重载+ Complex operator+(Complex &c); //普通加法函数 Complex myAdd(Complex &c1, Complex &c2); private: T a; T b; }; //友元函数的实现 template ostream& operator<<(ostream &out, Complex &c) { out< Complex ::Complex(T a, T b) { this->a = a; this->b = b; } template Complex Complex ::operator+(Complex &c) { Complex temp(this->a + c.a, this->b + c.b); return temp; } template Complex Complex ::myAdd(Complex &c1, Complex &c2) { Complex temp(c1.a + c2.a, c1.b + c2.b); return temp; } int main() { Complex c1(1,2); Complex c2(3,4); Complex c = c1 + c2; cout<
回报找不到这个模板。我认为出问题的原因是:
这里试图将模板的某个特化声明成类的友元。
在规则中这是不被允许的。
这里再仔细讲解一下这个规则:
如果普通的模板函数声明在内的内部,定义在类的外部,不管是否处于同一个文件,就跟普通的函数一样,不会出现任何错误提示。但是如果是友元函数就会出现报错,是因为有二次编译这个机制存在。在编译器进行编译的时候,编译器会产生类的模板函数的声明,当时实际确认类型后调用的时候,会根据调用的类型进行再次帮我们生成对应类型的函数声明和定义。我们称之为二次编译。同样,因为这个机制,会经常报错找不到类的函数的实现。在模板类的友元函数外部定义时,也会出现这个错误。
解决方法是 “ 类的前置声明和函数的前置声明 ”。如下:
#includeusing namespace std; template class Complex; template ostream & operator << (ostream & out, const Complex &c); template class Complex { //友元函数实现运算符重载 friend ostream& operator<<<>(ostream &out, Complex &c); public: Complex(T a, T b); //运算符重载+ Complex operator+(Complex &c); //普通加法函数 Complex myAdd(Complex &c1, Complex &c2); private: T a; T b; }; //友元函数的实现 template ostream& operator<<(ostream &out, Complex &c) { out << c.a << " + " << c.b << "i"; return out; } //函数的实现 template Complex ::Complex(T a, T b) { this->a = a; this->b = b; } template Complex Complex ::operator+(Complex &c) { Complex temp(this->a + c.a, this->b + c.b); return temp; } template Complex Complex ::myAdd(Complex &c1, Complex &c2) { Complex temp(c1.a + c2.a, c1.b + c2.b); return temp; } int main() { Complex c1(1, 2); Complex c2(3, 4); Complex c = c1 + c2; cout << c << endl; return 0; }
在所应用的类前提前声明。声明和定义分别在不同的文件(模板函数、模板友元)
类的声明和实现,分别在不同的文件下,需要增加一个hpp文件支持。或者尽量将模板函数与模板友元放在一个文件下。类的声明与函数的声明写在.h文件
类的实现及函数的实现写在.cpp文件
将.cpp文件改成.hpp文件
在主函数中调用.hpp文件,而不是引用.h文件
如果碰到.h和.hpp文件都存在的情况下,引用.hpp文件。demo2.h文件
存放类的声明和函数的声明
#includeusing namespace std; //类的前置声明 template class Complex; //友元函数的声明 template ostream& operator<<(ostream &out, Complex &c); template class Complex { //友元函数实现运算符重载 friend ostream& operator<< (ostream &out, Complex &c); public: Complex(T a, T b); //运算符重载+ Complex operator+(Complex &c); //普通加法函数 Complex myAdd(Complex &c1, Complex &c2); private: T a; T b; }; demo2.hpp文件
包括模板函数的实现
#include "demo2.h" //友元函数的实现 templateostream& operator<<(ostream &out, Complex &c) { out< Complex ::Complex(T a, T b) { this->a = a; this->b = b; } template Complex Complex ::operator+(Complex &c) { Complex temp(this->a + c.a, this->b + c.b); return temp; } template Complex Complex ::myAdd(Complex &c1, Complex &c2) { Complex temp(c1.a + c2.a, c1.b + c2.b); return temp; } main.cpp文件
需要调用hpp文件
```cpp #includeusing namespace std; #include "demo2.hpp" int main() { Complex c1(1,2); Complex c2(3,4); Complex c = c1 + c2; cout< 此处借鉴
链接:https://www.jianshu.com/p/70ca94872418



