OpenCV 的 type.hpp 头文件里包含了基本的数据类型,它们都是以类的形式定义的,例如 Complex,Point 等。
下面简单剖析 Point 的源代码,并借此学习 C++ 的一些基础知识。
1 template class Point_
1.1 模板类定义
/* 1) template<typename _Tp> * - specify that a template is being declared and a type argument _Tp will be used * - _Tp is used exactly like other type name */ template<typename _Tp> class Point_ { public: /* 2) define an alias for a type with the using or typedef syntax */ typedef _Tp value_type; /* 3) constructor * - a member with the same name as its class * - its declaration specifies an argument list but has no return type * - its job is to initialize an object of its class */ Point_(); Point_(_Tp _x, _Tp _y); Point_(const Point_& pt); Point_(const Size_<_Tp>& sz); Point_(const Vec<_Tp, 2>& v); /* 4) assignment operator */ Point_& operator = (const Point_& pt); /* 5) conversion operator * - a special kind of member function that converts a value of a class type * to a value of some other type. * - its general form is: operator type() const; */ //! conversion to another data type template<typename _Tp2> operator Point_<_Tp2>() const; //! conversion to the old-style C structures operator Vec<_Tp, 2>() const; /* 6) member functions */ //! dot product _Tp dot(const Point_& pt) const; //! dot product computed in double-precision arithmetics double ddot(const Point_& pt) const; //! cross-product double cross(const Point_& pt) const; //! checks whether the point is inside the specified rectangle bool inside(const Rect_<_Tp>& r) const; /* 7) member data */ _Tp x, y; //< the point coordinates }; /* 8) typedef * - type aliases are defined for convenience */ typedef Point_<int> Point2i; typedef Point_<float> Point2f; typedef Point_<double> Point2d; typedef Point2i Point;
1.2 构造函数实现
/* constructors implementation */ // 1) default template<typename _Tp> inline Point_<_Tp>::Point_() : x(0), y(0) {} // 2) specify x and y template<typename _Tp> inline Point_<_Tp>::Point_(_Tp _x, _Tp _y) : x(_x), y(_y) {} // 3) Point_ template<typename _Tp> inline Point_<_Tp>::Point_(const Point_& pt) : x(pt.x), y(pt.y) {} // 4) Size_<_Tp> template<typename _Tp> inline Point_<_Tp>::Point_(const Size_<_Tp>& sz) : x(sz.width), y(sz.height) {} // 5) Vec<_Tp, 2> template<typename _Tp> inline Point_<_Tp>::Point_(const Vec<_Tp,2>& v) : x(v[0]), y(v[1]) {}
第四个和第五个构造函数,分别使用了 Size_<_Tp> 和 Vec<_Tp, 2>, 下面来看看它们各自的定义
template class Size_
template<typename _Tp> class Size_ { public: typedef _Tp value_type; //! various constructors Size_(); Size_(_Tp _width, _Tp _height); Size_(const Size_& sz); Size_(const Point_<_Tp>& pt); Size_& operator = (const Size_& sz); //! the area (width*height) _Tp area() const; //! conversion of another data type. template<typename _Tp2> operator Size_<_Tp2>() const; _Tp width, height; // the width and the height }; typedef Size_<int> Size2i; typedef Size_<float> Size2f; typedef Size_<double> Size2d; typedef Size2i Size;
template class Vec (in matx.hpp)
/* The Vec class is commonly used to describe pixel types of multi-channel arrays */ template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1> { public: typedef _Tp value_type; enum { depth = Matx<_Tp, cn, 1>::depth, channels = cn, type = CV_MAKETYPE(depth, channels) }; //! default constructor Vec(); Vec(_Tp v0); //!< 1-element vector constructor Vec(_Tp v0, _Tp v1); //!< 2-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2); //!< 3-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 4-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 5-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 6-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 7-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 8-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 9-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 10-element vector constructor Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13); //!< 14-element vector constructor explicit Vec(const _Tp* values); Vec(const Vec<_Tp, cn>& v); static Vec all(_Tp alpha); //! per-element multiplication Vec mul(const Vec<_Tp, cn>& v) const; //! conjugation (makes sense for complex numbers and quaternions) Vec conj() const; /*! cross product of the two 3D vectors. For other dimensionalities the exception is raised */ Vec cross(const Vec& v) const; //! conversion to another data type template<typename T2> operator Vec<T2, cn>() const; /*! element access */ const _Tp& operator [](int i) const; _Tp& operator[](int i); const _Tp& operator ()(int i) const; _Tp& operator ()(int i); Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp); Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp); template<typename _T2> Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp); }; /* short aliases for Vec<T,n> */ typedef Vec<uchar, 2> Vec2b; typedef Vec<uchar, 3> Vec3b; typedef Vec<uchar, 4> Vec4b; typedef Vec<short, 2> Vec2s; typedef Vec<short, 3> Vec3s; typedef Vec<short, 4> Vec4s; typedef Vec<ushort, 2> Vec2w; typedef Vec<ushort, 3> Vec3w; typedef Vec<ushort, 4> Vec4w; typedef Vec<int, 2> Vec2i; typedef Vec<int, 3> Vec3i; typedef Vec<int, 4> Vec4i; typedef Vec<int, 6> Vec6i; typedef Vec<int, 8> Vec8i; typedef Vec<float, 2> Vec2f; typedef Vec<float, 3> Vec3f; typedef Vec<float, 4> Vec4f; typedef Vec<float, 6> Vec6f; typedef Vec<double, 2> Vec2d; typedef Vec<double, 3> Vec3d; typedef Vec<double, 4> Vec4d; typedef Vec<double, 6> Vec6d;
显然 Vec 继承于 Matx<_Tp, cn, 1>, 于是追本溯源,看其 template class Matx 的定义
// Template class for small matrices whose type and size are known at compilation time template<typename _Tp, int m, int n> class Matx { public: enum { depth = DataType<_Tp>::depth, rows = m, cols = n, channels = rows*cols, type = CV_MAKETYPE(depth, channels), shortdim = (m < n ? m : n) }; typedef _Tp value_type; typedef Matx<_Tp, m, n> mat_type; typedef Matx<_Tp, shortdim, 1> diag_type; //! default constructor Matx(); Matx(_Tp v0); //!< 1x1 matrix Matx(_Tp v0, _Tp v1); //!< 1x2 or 2x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2); //!< 1x3 or 3x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 1x4, 2x2 or 4x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 1x5 or 5x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 1x6, 2x3, 3x2 or 6x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 1x7 or 7x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 1x8, 2x4, 4x2 or 8x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 1x9, 3x3 or 9x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 1x10, 2x5 or 5x2 or 10x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11); //!< 1x12, 2x6, 3x4, 4x3, 6x2 or 12x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13); //!< 1x14, 2x7, 7x2 or 14x1 matrix Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9, _Tp v10, _Tp v11, _Tp v12, _Tp v13, _Tp v14, _Tp v15); //!< 1x16, 4x4 or 16x1 matrix explicit Matx(const _Tp* vals); //!< initialize from a plain array static Matx all(_Tp alpha); static Matx zeros(); static Matx ones(); static Matx eye(); static Matx diag(const diag_type& d); static Matx randu(_Tp a, _Tp b); static Matx randn(_Tp a, _Tp b); //! dot product computed with the default precision _Tp dot(const Matx<_Tp, m, n>& v) const; //! dot product computed in double-precision arithmetics double ddot(const Matx<_Tp, m, n>& v) const; //! conversion to another data type template<typename T2> operator Matx<T2, m, n>() const; //! change the matrix shape template<int m1, int n1> Matx<_Tp, m1, n1> reshape() const; //! extract part of the matrix template<int m1, int n1> Matx<_Tp, m1, n1> get_minor(int i, int j) const; //! extract the matrix row Matx<_Tp, 1, n> row(int i) const; //! extract the matrix column Matx<_Tp, m, 1> col(int i) const; //! extract the matrix diagonal diag_type diag() const; //! transpose the matrix Matx<_Tp, n, m> t() const; //! invert the matrix Matx<_Tp, n, m> inv(int method=DECOMP_LU, bool *p_is_ok = NULL) const; //! solve linear system template<int l> Matx<_Tp, n, l> solve(const Matx<_Tp, m, l>& rhs, int flags=DECOMP_LU) const; Vec<_Tp, n> solve(const Vec<_Tp, m>& rhs, int method) const; //! multiply two matrices element-wise Matx<_Tp, m, n> mul(const Matx<_Tp, m, n>& a) const; //! divide two matrices element-wise Matx<_Tp, m, n> div(const Matx<_Tp, m, n>& a) const; //! element access const _Tp& operator ()(int i, int j) const; _Tp& operator ()(int i, int j); //! 1D element access const _Tp& operator ()(int i) const; _Tp& operator ()(int i); Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_AddOp); Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_SubOp); template<typename _T2> Matx(const Matx<_Tp, m, n>& a, _T2 alpha, Matx_ScaleOp); Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_MulOp); Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_DivOp); template<int l> Matx(const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b, Matx_MatMulOp); Matx(const Matx<_Tp, n, m>& a, Matx_TOp); _Tp val[m*n]; //< matrix elements }; typedef Matx<float, 1, 2> Matx12f; typedef Matx<double, 1, 2> Matx12d; typedef Matx<float, 1, 3> Matx13f; typedef Matx<double, 1, 3> Matx13d; typedef Matx<float, 1, 4> Matx14f; typedef Matx<double, 1, 4> Matx14d; typedef Matx<float, 1, 6> Matx16f; typedef Matx<double, 1, 6> Matx16d; typedef Matx<float, 2, 1> Matx21f; typedef Matx<double, 2, 1> Matx21d; typedef Matx<float, 3, 1> Matx31f; typedef Matx<double, 3, 1> Matx31d; typedef Matx<float, 4, 1> Matx41f; typedef Matx<double, 4, 1> Matx41d; typedef Matx<float, 6, 1> Matx61f; typedef Matx<double, 6, 1> Matx61d; typedef Matx<float, 2, 2> Matx22f; typedef Matx<double, 2, 2> Matx22d; typedef Matx<float, 2, 3> Matx23f; typedef Matx<double, 2, 3> Matx23d; typedef Matx<float, 3, 2> Matx32f; typedef Matx<double, 3, 2> Matx32d; typedef Matx<float, 3, 3> Matx33f; typedef Matx<double, 3, 3> Matx33d; typedef Matx<float, 3, 4> Matx34f; typedef Matx<double, 3, 4> Matx34d; typedef Matx<float, 4, 3> Matx43f; typedef Matx<double, 4, 3> Matx43d; typedef Matx<float, 4, 4> Matx44f; typedef Matx<double, 4, 4> Matx44d; typedef Matx<float, 6, 6> Matx66f; typedef Matx<double, 6, 6> Matx66d;
再看看其中一个构造函数 Matx(_Tp v0, _Tp v1, _Tp v2) 的实现
template<typename _Tp, int m, int n> inline Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2) { CV_StaticAssert(channels >= 3, "Matx should have at least 3 elements."); val[0] = v0; val[1] = v1; val[2] = v2; for(int i = 3; i < channels; i++) val[i] = _Tp(0); }
最后回到 Vec 构造函数 Vec(_Tp v0, _Tp v1) 的实现
template<typename _Tp, int cn> inline Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1) : Matx<_Tp, cn, 1>(v0, v1) {}
至此,Size_<_Tp> 和 Vec<_Tp, 2> 也就清晰可见了
1.3 成员函数
回到模板类 Point_ 的成员函数,首先看看赋值运算符的实现
1) 赋值操作符
// 1) assignment operator template<typename _Tp> inline Point_<_Tp>& Point_<_Tp>::operator = (const Point_& pt) { x = pt.x; y = pt.y; return *this; }
注意其返回值为 *this,是实例 pt 自身的引用。
在 <Effective C++> 书中,有对此的解释,item 10 - have assignment operators return a reference to this*,详细的解释如下:
/* 1) chain of assignments */ // assignment returns a reference to its left-hand argument int x, y, z; x = y = z = 15; // right-associative x = (y = (z = 15)); // more clear way /* 2) assignment operators for classes */ class Widget{ public: ... // return type is a reference to the current class Widget& operator=(const Widget& rhs) { ... return *this; //return the left-hand object } ... }; // apply to all assignment operators class Widget{ public: ... // +=, -=, *= Widget& operator+= (const Widget& rhs) { ... return *this; } // it applies even if the parameter type is unconventional Widget& operator=(int rhs) { ... return *this; } ... }; // this convention is followed by all built-in types and // by all the types in STL(e.g., string, vector, complex)
2) 转换操作符
// 2) conversion operator // - Point_<_Tp2>() // - Vec<_Tp, 2>() template<typename _Tp> template<typename _Tp2> inline Point_<_Tp>::operator Point_<_Tp2>() const { return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); } template<typename _Tp> inline Point_<_Tp>::operator Vec<_Tp, 2>() const { return Vec<_Tp, 2>(x, y); }
saturate_cast
3) 成员函数 dot 等
// 3) member functions: dot, ddot, cross, inside template<typename _Tp> inline _Tp Point_<_Tp>::dot(const Point_& pt) const { return saturate_cast<_Tp>(x*pt.x + y*pt.y); } template<typename _Tp> inline double Point_<_Tp>::ddot(const Point_& pt) const { return (double)x*pt.x + (double)y*pt.y; } template<typename _Tp> inline double Point_<_Tp>::cross(const Point_& pt) const { return (double)x*pt.y - (double)y*pt.x; } template<typename _Tp> inline bool Point_<_Tp>::inside( const Rect_<_Tp>& r ) const { return r.contains(*this); }
成员函数 inside 里面调用了 Rect_ 的 contains 成员函数。于是继续剖析,寻找到模板类 Rect_ 的定义和其成员函数 contains 的实现如下:
// Template class for 2D rectangles template<typename _Tp> class Rect_ { public: typedef _Tp value_type; //! various constructors Rect_(); Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height); Rect_(const Rect_& r); Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz); Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2); Rect_& operator = ( const Rect_& r ); //! the top-left corner Point_<_Tp> tl() const; //! the bottom-right corner Point_<_Tp> br() const; //! size (width, height) of the rectangle Size_<_Tp> size() const; //! area (width*height) of the rectangle _Tp area() const; //! conversion to another data type template<typename _Tp2> operator Rect_<_Tp2>() const; //! checks whether the rectangle contains the point bool contains(const Point_<_Tp>& pt) const; _Tp x, y, width, height; //< the top-left corner, as well as width and height of the rectangle }; // type aliases defined for convenience typedef Rect_<int> Rect2i; typedef Rect_<float> Rect2f; typedef Rect_<double> Rect2d; typedef Rect2i Rect; // the implementation of member function contains template<typename _Tp> inline bool Rect_<_Tp>::contains(const Point_<_Tp>& pt) const { return x <= pt.x && pt.x < x + width && y <= pt.y && pt.y < y + height; }
附: 成员函数内的参数是 pass-by-reference-to-const 的形式,该形式在 <Effective C++> 书中也有详细的解释
item 20 - Prefer pass-by-reference-to-const to pass-by-value
/************************************************** * 1. more efficient ***************************************************/ // class Person and its subclass Student class Person{ public: Person(); // parameters omitted for simplicity virtual ~Person(); ... private: std::string name; std::string address; }; class Student: public Person{ public: Student(); // parameters again omitted ~Student(); ... private: std::string schoolName; std::string schoolAddress; }; // 1) pass-by-value bool validateStudent(Student s); // inefficient: need to construct a Student object, two string objects, // a Person object, two string objects and also destruct those objects Student plato; bool platoOK = validateStudent(plato); // 2) pass-by-reference-to-const // efficient: no constructors or destructors are called bool validateStudent(const Student& s); /************************************************* * 2. avoid slicing **************************************************/ class Window{ public: ... std::string name() const; // return name of window virtual void display() const; // draw window and contents }; class WindowWithScrollBars{ public: ... virtual void display() const; }; // 1) pass-by-value is incorrect void printNameAndDisplay(Window w) { std::cout << w.name(); w.display(); } // WindowWithScrollBars object will be sliced off WindowWithScrollBars wwsb; printNameAndDisplay(wwsb); // 2) pass-by-reference-to-const is correct void printNameAndDisplay(const Window& w) { std::cout << w.name(); w.display(); }
1.4 运算符重载(非成员函数)
这几个操作符的重载都比较简单,主要涉及不同数据类型间的运算,同时也需注意返回值与函数参数 const 类型的关系
// 1) +=, -=, *=, /= // += template<typename _Tp> static inline Point_<_Tp>& operator += (Point_<_Tp>& a, const Point_<_Tp>& b) { a.x += b.x; a.y += b.y; return a; } // -= template<typename _Tp> static inline Point_<_Tp>& operator -= (Point_<_Tp>& a, const Point_<_Tp>& b) { a.x -= b.x; a.y -= b.y; return a; } // *= template<typename _Tp> static inline Point_<_Tp>& operator *= (Point_<_Tp>& a, int b) { a.x = saturate_cast<_Tp>(a.x * b); a.y = saturate_cast<_Tp>(a.y * b); return a; } template<typename _Tp> static inline Point_<_Tp>& operator *= (Point_<_Tp>& a, float b) { a.x = saturate_cast<_Tp>(a.x * b); a.y = saturate_cast<_Tp>(a.y * b); return a; } template<typename _Tp> static inline Point_<_Tp>& operator *= (Point_<_Tp>& a, double b) { a.x = saturate_cast<_Tp>(a.x * b); a.y = saturate_cast<_Tp>(a.y * b); return a; } // /= template<typename _Tp> static inline Point_<_Tp>& operator /= (Point_<_Tp>& a, int b) { a.x = saturate_cast<_Tp>(a.x / b); a.y = saturate_cast<_Tp>(a.y / b); return a; } template<typename _Tp> static inline Point_<_Tp>& operator /= (Point_<_Tp>& a, float b) { a.x = saturate_cast<_Tp>(a.x / b); a.y = saturate_cast<_Tp>(a.y / b); return a; } template<typename _Tp> static inline Point_<_Tp>& operator /= (Point_<_Tp>& a, double b) { a.x = saturate_cast<_Tp>(a.x / b); a.y = saturate_cast<_Tp>(a.y / b); return a; } // 2) norm template<typename _Tp> static inline double norm(const Point_<_Tp>& pt) { return std::sqrt((double)pt.x*pt.x + (double)pt.y*pt.y); } // 3) ==, != template<typename _Tp> static inline bool operator == (const Point_<_Tp>& a, const Point_<_Tp>& b) { return a.x == b.x && a.y == b.y; } template<typename _Tp> static inline bool operator != (const Point_<_Tp>& a, const Point_<_Tp>& b) { return a.x != b.x || a.y != b.y; } // 4) +, binary -, unary - // + template<typename _Tp> static inline Point_<_Tp> operator + (const Point_<_Tp>& a, const Point_<_Tp>& b) { return Point_<_Tp>( saturate_cast<_Tp>(a.x + b.x), saturate_cast<_Tp>(a.y + b.y) ); } // binary - template<typename _Tp> static inline Point_<_Tp> operator - (const Point_<_Tp>& a, const Point_<_Tp>& b) { return Point_<_Tp>( saturate_cast<_Tp>(a.x - b.x), saturate_cast<_Tp>(a.y - b.y) ); } // unary - template<typename _Tp> static inline Point_<_Tp> operator - (const Point_<_Tp>& a) { return Point_<_Tp>( saturate_cast<_Tp>(-a.x), saturate_cast<_Tp>(-a.y) ); } // 5) mixed mode * template<typename _Tp> static inline Point_<_Tp> operator * (const Point_<_Tp>& a, int b) { return Point_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b) ); } template<typename _Tp> static inline Point_<_Tp> operator * (int a, const Point_<_Tp>& b) { return Point_<_Tp>( saturate_cast<_Tp>(b.x*a), saturate_cast<_Tp>(b.y*a) ); } template<typename _Tp> static inline Point_<_Tp> operator * (const Point_<_Tp>& a, float b) { return Point_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b) ); } template<typename _Tp> static inline Point_<_Tp> operator * (float a, const Point_<_Tp>& b) { return Point_<_Tp>( saturate_cast<_Tp>(b.x*a), saturate_cast<_Tp>(b.y*a) ); } template<typename _Tp> static inline Point_<_Tp> operator * (const Point_<_Tp>& a, double b) { return Point_<_Tp>( saturate_cast<_Tp>(a.x*b), saturate_cast<_Tp>(a.y*b) ); } template<typename _Tp> static inline Point_<_Tp> operator * (double a, const Point_<_Tp>& b) { return Point_<_Tp>( saturate_cast<_Tp>(b.x*a), saturate_cast<_Tp>(b.y*a) ); } template<typename _Tp> static inline Point_<_Tp> operator * (const Matx<_Tp, 2, 2>& a, const Point_<_Tp>& b) { Matx<_Tp, 2, 1> tmp = a * Vec<_Tp,2>(b.x, b.y); return Point_<_Tp>(tmp.val[0], tmp.val[1]); } template<typename _Tp> static inline Point3_<_Tp> operator * (const Matx<_Tp, 3, 3>& a, const Point_<_Tp>& b) { Matx<_Tp, 3, 1> tmp = a * Vec<_Tp,3>(b.x, b.y, 1); return Point3_<_Tp>(tmp.val[0], tmp.val[1], tmp.val[2]); } // 6) mixed mode / template<typename _Tp> static inline Point_<_Tp> operator / (const Point_<_Tp>& a, int b) { Point_<_Tp> tmp(a); tmp /= b; return tmp; } template<typename _Tp> static inline Point_<_Tp> operator / (const Point_<_Tp>& a, float b) { Point_<_Tp> tmp(a); tmp /= b; return tmp; } template<typename _Tp> static inline Point_<_Tp> operator / (const Point_<_Tp>& a, double b) { Point_<_Tp> tmp(a); tmp /= b; return tmp; }
1.5 使用实例
每一次类模板的实例化,都单独构成一个独立的类。例如, Point_<int> 和 Point_<float> 便是两个完全独立的类
// type aliases are defined for convenience typedef Point_<int> Point2i; typedef Point_<float> Point2f; typedef Point_<double> Point2d; typedef Point2i Point; // Example Point2f a(0.3f, 0.f), b(0.f, 0.4f); Point pt = (a + b)*10.f; cout << pt.x << ", " << pt.y << endl;