C++
中有一个重要特性,那就是模板类型。类似于Objective-C中的泛型。C++通过类模板来实现泛型支持。

1 基础的类模板

类模板,可以定义相同的操作,拥有不同数据类型的成员属性。

通常使用template来声明。告诉编译器,碰到T不要报错,表示一种泛型.

如下,声明一个普通的类模板:

template <typename T>
class Complex{public://构造函数Complex(T a, T b){this->a = a;this->b = b;}//运算符重载Complex<T> operator+(Complex &c){Complex<T> tmp(this->a+c.a, this->b+c.b);return tmp;}private:T a;T b;
}int main()
{//对象的定义,必须声明模板类型,因为要分配内容Complex<int> a(10,20);  Complex<int> b(20,30);Complex<int> c = a + b;return 0;
}

2 模板类的继承

在模板类的继承中,需要注意以下几点:

  • 如果父类自定义了构造函数,记得子类要使用构造函数列表来初始化
  • 继承的时候,如果子类不是模板类,则必须指明当前的父类的类型,因为要分配内存空间
  • 继承的时候,如果子类是模板类,要么指定父类的类型,要么用子类的泛型来指定父类
template <typename T>
class Parent{
public:Parent(T p){this->p = p;}private:T p;
};//如果子类不是模板类,需要指明父类的具体类型
class ChildOne:public Parent<int>{public:ChildOne(int a,int b):Parent(b){this->cone = a;}private:int cone;
};//如果子类是模板类,可以用子类的泛型来表示父类
template <typename T>
class ChildTwo:public Parent<T>{public:ChildTwo(T a, T b):Parent<T>(b){this->ctwo = a;}private:T ctwo;
};

3 内部声明定义普通模板函数和友元模板函数

普通模板函数和友元模板函数,声明和定义都写在类的内部,也不会有什么报错。

template <typename T>
class Complex {//友元函数实现运算符重载friend ostream& operator<<(ostream &out, Complex &c){out<<c.a << " + " << c.b << "i";return out;}public:Complex(T a, T b){this->a = a;this->b = b;}//运算符重载+Complex operator+(Complex &c){Complex temp(this->a + c.a, this->b + c.b);return temp;}//普通加法函数Complex myAdd(Complex &c1, Complex &c2){Complex temp(c1.a + c2.a, c1.b + c2.b);return temp;}private:T a;T b;
};int main()
{Complex<int> c1(1,2);Complex<int> c2(3,4);Complex<int> c = c1 + c2;cout<<c<<endl;return 0;
}

4 内部声明友元模板函数+外部定义友元模板函数

如果普通的模板函数声明在内的内部,定义在类的外部,不管是否处于同一个文件,就跟普通的函数一样,不会出现任何错误提示。但是如果是友元函数就会出现报错,是因为有二次编译这个机制存在。

4.1 模板类和模板函数的机制

在编译器进行编译的时候,编译器会产生类的模板函数的声明,当时实际确认类型后调用的时候,会根据调用的类型进行再次帮我们生成对应类型的函数声明和定义。我们称之为二次编译。同样,因为这个机制,会经常报错找不到类的函数的实现。在模板类的友元函数外部定义时,也会出现这个错误。解决方法是 “ 类的前置声明和函数的前置声明 ”。

  • 按照普通模板函数的样式处理友元函数
#include <iostream>
using namespace std;template <typename T>
class Complex {//友元函数实现运算符重载friend ostream& operator<<(ostream &out, Complex<T> &c);public:Complex(T a, T b);//运算符重载+Complex<T> operator+(Complex<T> &c);//普通加法函数Complex<T> myAdd(Complex<T> &c1, Complex<T> &c2);private:T a;T b;
};//友元函数的实现
template <typename T>
ostream& operator<<(ostream &out, Complex<T> &c)
{out<<c.a << " + " << c.b << "i";return out;
}//函数的实现
template <typename T>
Complex<T>::Complex(T a, T b)
{this->a = a;this->b = b;
}template <typename T>
Complex<T> Complex<T>::operator+(Complex<T> &c)
{Complex temp(this->a + c.a, this->b + c.b);return temp;
}template <typename T>
Complex<T> Complex<T>::myAdd(Complex<T> &c1, Complex<T> &c2)
{Complex temp(c1.a + c2.a, c1.b + c2.b);return temp;
}int main()
{Complex<int> c1(1,2);Complex<int> c2(3,4);Complex<int> c = c1 + c2;cout<<c<<endl;return 0;
}
  • 友元函数的定义写在类的外部–错误信息
Undefined symbols for architecture x86_64:"operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, Complex<int>&)", referenced from:_main in demo1.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

上面的错误信息,就是典型的二次编译的错误信息,找不到友元函数的函数实现。所以,如果友元模板函数的定义写在函数的外部,需要进行类和函数的前置声明,来让编译器找到函数的实现

4.2 前置声明解决二次编译问题

  • 类的前置声明
  • 友元模板函数的前置声明
  • 友元模板函数声明需要增加泛型支持

5 声明和定义分别在不同的文件(模板函数、模板友元)

类的声明和实现,分别在不同的文件下,需要增加一个hpp文件支持。或者尽量将模板函数与模板友元放在一个文件下。

  • 类的声明与函数的声明写在.h文件
  • 类的实现及函数的实现写在.cpp文件
  • 将.cpp文件改成.hpp文件
  • 在主函数中调用.hpp文件,而不是引用.h文件

如果碰到.h和.hpp文件都存在的情况下,引用.hpp文件。

demo2.h文件
存放类的声明和函数的声明

#include <iostream>
using namespace std;//类的前置声明
template <typename T>
class Complex;//友元函数的声明
template <typename T>
ostream& operator<<(ostream &out, Complex<T> &c);template <typename T>
class Complex {//友元函数实现运算符重载friend ostream& operator<< <T> (ostream &out, Complex<T> &c);public:Complex(T a, T b);//运算符重载+Complex<T> operator+(Complex<T> &c);//普通加法函数Complex<T> myAdd(Complex<T> &c1, Complex<T> &c2);private:T a;T b;
};

demo2.hpp文件
包括模板函数的实现

#include "demo2.h"//友元函数的实现
template <typename T>
ostream& operator<<(ostream &out, Complex<T> &c)
{out<<c.a << " + " << c.b << "i";return out;
}//函数的实现
template <typename T>
Complex<T>::Complex(T a, T b)
{this->a = a;this->b = b;
}template <typename T>
Complex<T> Complex<T>::operator+(Complex<T> &c)
{Complex temp(this->a + c.a, this->b + c.b);return temp;
}template <typename T>
Complex<T> Complex<T>::myAdd(Complex<T> &c1, Complex<T> &c2)
{Complex temp(c1.a + c2.a, c1.b + c2.b);return temp;
}

main.cpp文件
需要调用hpp文件

#include <iostream>
using namespace std;
#include "demo2.hpp"int main()
{Complex<int> c1(1,2);Complex<int> c2(3,4);Complex<int> c = c1 + c2;cout<<c<<endl;return 0;
}

C++类模板和模板类相关推荐

  1. 各类商会协会单位类织梦模板(带手机端)

    模板名称: 各类商会协会单位类织梦模板(带手机端)+PC+移动端+利于SEO优化 模板介绍: 织梦最新内核开发的模板,该模板属于企业通用.商会.协会.事业单位类等设备类企业都可使用, 这款模板使用范围 ...

  2. C++知识点61——typename与class、模板编程与继承、模板类和友元、类模板与static成员

    一.typename与class的异同 1.啥时候既可以使用typename,又可以使用class? 当表示模板参数的时候,二者没有区别 2.啥时候只能使用typename,不能使用class? 当模 ...

  3. C++知识点59——类模板(4、类模板的模板参数是一个类模板)

    接上一篇文章https://blog.csdn.net/Master_Cui/article/details/111824152 七.类模板的模板参数是一个模板类 类模板的模板参数本身可以是一个类模板 ...

  4. 泛函编程—模板函数_类模板

    函数业务逻辑一样,只是函数参数类型不同 函数模板的本质:类型参数化--泛型编程 语法: template <typename T> template <class T1,class ...

  5. 定义一个类mymath_C++:模板类

    22.模板类 22.1 模板类 模板是泛型编程的基础,那什么是泛型编程呢?泛型编程是一种独立于任何特定数据类型编写代码的方式. C++标准模板库中的数据容器.迭代器和算法,都是泛型编程的例子,它们都使 ...

  6. binarytreenode”使用 类 模板 需要 模板 参数列表_c++1117 模板核心知识(一)—— 函数模板...

    目录 定义函数模板 使用函数模板 两阶段翻译 Two-Phase Translation 模板的编译和链接问题 多模板参数 引入额外模板参数作为返回值类型 让编译器自己找出返回值类型 将返回值声明为两 ...

  7. 8-1日复习 模板函数 模板类

    函数的重载: //函数重载 感觉还是太繁琐 引入函数模板的概念#include <iostream>using namespace std;int add(int x , int y) { ...

  8. 问模板函数、函数模板,模板类、类模板的区别的问题?

    问模板函数.函数模板,模板类.类模板的区别的问题? - 赵保龙 - 博客园 问模板函数.函数模板,模板类.类模板的区别的问题? 在C++中有好几个这样的术语,但是我们很多时候用的并不正确,几乎是互相替 ...

  9. 类模板,多种类型的类模板,自定义类模板,类模板的默认类型,数组的模板实现,友元和类模板,友元函数,类模板与静态变量,类模板与普通类之间互相继承,类模板作为模板参数,类嵌套,类模板嵌套,类包装器

     1.第一个最简单的类模板案例 #include "mainwindow.h" #include <QApplication> #include <QPush ...

  10. 关于模板函数/模板类编译成DLL

    ]关于模板函数/模板类编译成DLL Posted on 2011-08-16 08:48 单鱼游弋 阅读( 353) 评论( 0) 编辑 收藏 要编译成DLL,就要声明和实现分开. 首先文件组织是这样 ...

最新文章

  1. Java 巨坑篇之无底深坑Long类型
  2. Xen Server二安装xc及管理xen主机
  3. maven 包的导入
  4. nssl1196-摘果子【树形依赖背包,dp】
  5. 图像处理中ct图的通道是多少_新一代安检CT机,智能安防领域又一明星产品
  6. oracle 批量给字段加注释,Oracle给表和字段添加注释
  7. HTTP性能测试工具wrk安装及使用
  8. 设计模式(八) : 结构型模式--装饰模式
  9. golang 打印变量类型
  10. 网络请求的null值处理
  11. 黑马程序员——Java基础知识——泛型、枚举
  12. 基于python的客流统计_基于深度学习的客流量统计方法
  13. Uipath Try Catch 妙用
  14. 分析:大数据失败案例及背后原因!
  15. 如何测量两组汇编指令的执行效率
  16. 网络摄像头工作原理_好,更好,最好以预算创建最终的远程工作者网络摄像头设置
  17. 计算机中什么是适配器及作用,什么是电脑适配器
  18. Cadence Allegro如何快速对齐器件
  19. 如何将iPhone照片从iCloud下载到Mac
  20. ESP8266上传DHT11数据给私人javaweb服务器实现网页查询数据的电路方案

热门文章

  1. Windows10 查看剪贴板(剪贴历史文字、图片)
  2. neo4j实现Betweenness Centrality算法
  3. 关于项目报告的写法问题
  4. 攻防世界reverse新手区——simple-unpack(upx脱壳)
  5. odbc驱动安装部署
  6. ucenter php版本,PHP优秀系统UCenter的MVC架构
  7. JAVA数据库课程设计—简易网上银行管理系统-java图形用户界面
  8. C#编程学习35:对MDB数据库的操作
  9. 利用Python下载PPT模板
  10. 压缩图片大小的java代码_java按比例压缩图片的源代码,用java如何把图片处理到指定大小...