因为看OpenCV源代码时候,发现自己很是吃力,所以做出如下总结,与大家分享。
接下来我给大家展示一小部分源代码:···(一定要往后看哦)···
接下来主要对标记0/1/2/3几处进行详细说明
语法解析:
0:类模板 + public继承
1:typedef typename 作用
2:构造函数,参数初始化列表
3:()重载
//子类
0: template<class Op, class VecOp> struct MorphRowFilter : public BaseRowFilter
{
1: typedef typename Op::rtype T;
2: MorphRowFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor)
{
ksize = _ksize;
anchor = _anchor;
}
3: void operator()(const uchar* src, uchar* dst, int width, int cn)
{
int i, j, k, _ksize = ksize*cn;
const T* S = (const T*)src;
Op op;
T* D = (T*)dst;
if( _ksize == cn )
{
for( i = 0; i < width*cn; i++ )
D[i] = S[i];
return;
}
int i0 = vecOp(src, dst, width, cn);
width *= cn;
for( k = 0; k < cn; k++, S++, D++ )
{
for( i = i0; i <= width - cn*2; i += cn*2 )
{
const T* s = S + i;
T m = s[cn];
for( j = cn*2; j < _ksize; j += cn )
m = op(m, s[j]);
D[i] = op(m, s[0]);
D[i+cn] = op(m, s[j]);
}
for( ; i < width; i += cn )
{
const T* s = S + i;
T m = s[0];
for( j = cn; j < _ksize; j += cn )
m = op(m, s[j]);
D[i] = m;
}
}
}
VecOp vecOp;
};
//父类(基类)
class CV_EXPORTS BaseColumnFilter
{
public:
//! the default constructor
BaseColumnFilter();
//! the destructor
virtual ~BaseColumnFilter();
//! the filtering operator. Must be overrided in the derived classes. The vertical border interpolation is done outside of the class.
virtual void operator()(const uchar** src, uchar* dst, int dststep,
int dstcount, int width) = 0;
//! resets the internal buffers, if any
virtual void reset();
int ksize, anchor;
};
0 :
template<class Op, class VecOp> struct MorphRowFilter : public BaseRowFilter
类模板 + public继承
解释:Op与VecOp只是抽象的名字, 定义了MorphRowFilter的模板类,并且共有继承了BaseRowFilter
用简单案例来说明 类模板:
//copyright @ hanshanbuleng
#include <iostream>
using namespace std;
//对于类的声明来说,我们会遇到两个或多个类,其功能是相同的,仅仅是数据类型不相同
//如以下,int float 类
//int 类型
class compare_int
{
public:
compare_int(int a, int b) //定义构造函数
{
x_ = a;
y_ = b;
}
int max() //利用三目运算符 求最大值
{
return (x_ > y_) ? x_ : y_;
}
int min() //利用三目运算符 求最小值
{
return (x_ < y_) ? x_ : y_;
}
private:
int x_;
int y_;
};
//float 类型
class compare_float
{
public:
compare_float(float a, float b) //定义构造函数
{
x_ = a;
y_ = b;
}
int max() //利用三目运算符 求最大值
{
return (x_ > y_) ? x_ : y_;
}
int min() //利用三目运算符 求最小值
{
return (x_ < y_) ? x_ : y_;
}
private:
float x_;
float y_;
};
//类模板
template <class numtype> //template <class numtype>
class compare //struct compare 在此处 class与struct可以替换
{
public:
compare(numtype a, numtype b) //定义构造函数
{
x_ = a;
y_ = b;
}
int max() //利用三目运算符 求最大值
{
return (x_ > y_) ? x_ : y_;
}
int min() //利用三目运算符 求最小值
{
return (x_ < y_) ? x_ : y_;
}
private:
numtype x_;
numtype y_;
};
int main()
{
int flag = 0; //0正确 -1错误
int value0;
float value1;
compare <int> hanshanbuleng0(10, 20); //用类模板的方式进行初始化
value0 = hanshanbuleng0.max();
printf("value0:%d \n", value0);
compare <float> hanshanbuleng1(10.0, 20.0); //用类模板的方式进行初始化
value1 = hanshanbuleng1.max();
printf("value0:%f \n", value1);
return flag;
}
1:
typedef typename Op::rtype T;
typedef typename 作用
语法让人看着费解 但是当我们知道其含义和用法,就很好理解了
将以上内容进行缩写:
template<class Op, class VecOp>
{
public:
typedef typename Op::rtype T; //与其等价typedef typename <Op>::rtype T
//...
};
我们删去不懂的 typename Op::
template<class Op, class VecOp>
class MorphRowFilter
{
public:
typedef rtype T;
//...
};
这样就看得很清晰了,MorphRowFilter::T是MorphRowFilter的嵌套类型定义,其实际等价于 rtype类型,也就是表明:
使用中声明 MorphRowFilter ::T INT; <==> rtype INT;
为什么使用typename关键字???
模板类型在实例化之前,编译器并不知道MorphRowFilter<Op>::T 是什么东西,事实上一共有三种可能:
静态数据成员
静态成员函数
嵌套类型
那么此时typename的作用就在此时体现出来了————定义就不再模棱两可。
typedef typename Op::rtype T; //与其等价typedef typename <Op>::rtype T
语句的真是面目是:
typedef创建了存在类型的别名,而typename告诉编译器MorphRowFilter<Op>::rtype 是一个类型而不是一个成员。
2:
MorphRowFilter( int _ksize, int _anchor ) : vecOp(_ksize, _anchor)
构造函数,参数初始化列表 ===》本程序中是 用参数初始化表 对数据成员初始化
用vecOp(_ksize, _anchor) 对数据成员VecOp vecOp 初始化
我们要想知道VecOp具体是什么类型,那么我们需要知道是谁调用了
template<class Op, class VecOp> struct MorphRowFilter : public BaseRowFilter
调用源码截取:
if( depth == CV_64F )
return Ptr<BaseRowFilter>(new MorphRowFilter< MinOp<double>, ErodeRowVec64f >(ksize, anchor));
==》 Op 对应 double, VecOp 对应 ErodeRowVec64f
引申:
通过显示调用父类的构造函数对父类数据成员进行初始化
使用初始化列表有两个原因:
原因1.必须这样做:
《C++ Primer》中提到在以下三种情况下需要使用初始化成员列表:
一、需要初始化的数据成员是对象的情况(这里包含了继承情况下,通过显示调用父类的构造函数对父类数据成员进行初始化);
二、需要初始化const修饰的类成员;
三、需要初始化引用成员数据
原因2.效率要求这样做:
类对象的构造顺序显示,进入构造函数体后,进行的是计算,是对成员变量的赋值操作,
显然,赋值和初始化是不同的,这样就体现出了效率差异,如果不用成员初始化类表,
那么类对自己的类成员分别进行的是一次隐式的默认构造函数的调用,和一次赋值操作符的调用,
如果是类对象,这样做效率就得不到保障。
3:
void operator()(const uchar* src, uchar* dst, int width, int cn)
()重载
运算符重载使得指定的运算符不仅实现原来有的功能,而且实现在函数中指定的新功能。
一般格式如下:
函数类型 operator 运算符名称 (形参表)
{
对运算符的重载处理
}
参考资料:
https://blog.youkuaiyun.com/zx3517288/article/details/48806785
https://blog.youkuaiyun.com/jinzhichaoshuiping/article/details/51672586