C++ 类模板
模板类是一个很有用的工具, 平常使用比较多的像std::vector, std::map, std::queue都是模板类, 可以说很方便. 但是背后的实现可以说是很复杂, 包括内存分配,包括快速访问. 我们之所以能这么方便的使用,全是站在了巨人的肩膀上.
模板定义的C++实体如下
- 类模板,可以是嵌套类
- 函数模板,可以是成员函数
- 别名模板 (C++11 起)
- 变量模板 (C++14 起)
- requires 与 concept (C++20 起)
本文主要介绍类模板和函数模板, 首先我们定义一个模板类
template<class T>
class MyClass
{
public:
MyClass(){};
explicit MyClass(const T& src):vec_(src){}
~MyClass(){}
const T& get_vec() const
{
return vec_;
}
MyClass<T>& operator+(const MyClass<T> r);
MyClass<T>& operator=(const MyClass<T> r);
public:
T vec_;
};
在这个类当中,我们定义了一个公有成员变量,这个变量可以被外部访问, 这个类可以作为一个基础类使用, 另外我们定义了两个构造函数和一个析构函数. 另外的函数包括返回成员的函数和两个操作符重载的函数;
接下来是关于类模板的实现了, 可以看到,这里面有一些内联函数,由于比较短, 写成内联的比较合适. 关于重载操作符的两个函数则在类外定义. 注意: 根据C++标准类模板的定义与实现都得在同一个.hpp文件里
template<class T> inline
MyClass<T>& MyClass<T>::operator=(const MyClass<T> r)
{
this->vec_ = r.vec_; //其中这里的this可以省略
return *this;
}
template<class T> inline
MyClass<T>& MyClass<T>::operator+(const MyClass<T> r)
{
this->vec_ = this->vec_ + r.vec_;//其中这里的this可以省略
return *this;
}
模板类的用途大多数的时候是用在公用库里面, 供他人调用
.这个类在逻辑上显得比较多余,但是可以拿来练手. 如果考虑将其实现为vector这样的类,那么得考虑动态内存分配, 考虑内存释放的问题,比较复杂.
另外多看优秀的源码可以帮我们提高代码能力, 如下面这段,我截取了 opencv里面的Rect_类的实现
,即矩形的实现
Rect.hpp
template<typename _Tp> class Rect_
{
public:
typedef _Tp value_type;
//! default constructor
Rect_();
Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);
Rect_(const Rect_& r);
Rect_(Rect_&& r);
Rect_& operator = ( const Rect_& r );
Rect_& operator = ( Rect_&& r );
Rect_& operator + ( const Rect_& r);
//! area (width*height) of the rectangle
_Tp area() const;
//! true if empty
bool empty() const;
_Tp x; //!< x coordinate of the top-left corner
_Tp y; //!< y coordinate of the top-left corner
_Tp width; //!< width of the rectangle
_Tp height; //!< height of the rectangle
};
template<typename _Tp> inline
Rect_<_Tp>::Rect_():x(0), y(0), width(0), height(0){}
template<typename _Tp> inline
Rect_<_Tp>::Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height)
: x(_x), y(_y), width(_width), height(_height){}
template<typename _Tp> inline
Rect_<_Tp>::Rect_(const Rect_& r)
: x(r.x), y(r.y), width(r.width), height(r.height){}
template<typename _Tp> inline
Rect_<_Tp>::Rect_(Rect_&& r)
: x(std::move(r.x)), y(std::move(r.y)), width(std::move(r.width)), height(std::move(r.height)){}
template<typename _Tp> inline
Rect_<_Tp>& Rect_<_Tp>::operator=(const Rect_<_Tp>& r)
{
x = r.x;
y = r.y;
width = r.width;
height = r.height;
return *this;
}
template<typename _Tp> inline
Rect_<_Tp>& Rect_<_Tp>::operator=( Rect_<_Tp>&& r)
{
x = std::move(r.x);
y = std::move(r.y);
width = std::move(r.width);
height = std::move(r.height);
return *this;
}
template<typename _Tp> inline
Rect_<_Tp>& Rect_<_Tp>::operator+( const Rect_<_Tp>& r)
{
x = r.x;
y = r.y;
width = r.width;
height = r.height;
return *this;
}
template<typename _Tp> inline
_Tp Rect_<_Tp>::area() const
{
return width*height;
}
template<typename _Tp> inline
bool Rect_<_Tp>::empty() const
{
return width <=0 || height <= 0;
}
注意:不要在.hpp文件中使用using namespace std这样的代码,很容易造成命名空间污染
Rect_类的实现,作为opencv的一个基础类型,使用场合还是很多的,可以看到他的构造函数比较丰富,而且我还删除了其中的一些和Point_类的相关的构造函数, 和成员函数. 另外我加了一个+号的操作符重载函数, 逻辑上来讲, 两个矩形相加的操作没太大意义
最后放上main函数
#include <iostream>
#include <string>
#include "MyClass.hpp"
#include "Rect.hpp"
using namespace std;
int main(int argc, char* argv[])
{
string vs ="blackshake";
string vp = "_hahha";
MyClass<string> myc(vs);
MyClass<string> r(vp);
myc = myc+r;
string str = myc.get_vec();
cout<<str;
Rect_<int> rect1(100, 35, 100, 200);
Rect_<int> rect2(rect1);
cout<<rect1.area();
cout<<rect1.empty();
return 0;
}
通过多看源码,可以学习别人的优秀技巧!
2020.01.17 --Zlatan