C++的四大特点是抽象、封装、多态、继承派生。个人理解为抽象是基础,封装和继承派生是方法,多态是工具。
一般来讲,对一个问题的抽象应该包括两个方面:数据抽象和行为抽象。前者描述某类对象的属性或状态,也就是此类对象区别于彼类对象的特征;后者描述的是某类对象的共同行为或功能特征。
类封装建立目的及作用:通过封装使一部分成员充当类与外部的接口,而将其他成员隐藏起来,这样就达到了对成员访问权限的合理控制,使不同类之间的相互影响减少到最低限度,进而增强了数据的安全性和简化程序编写工作。同时,封装使得代码变得模块化,更加便于维护和运营。
1、类属性的定义:如果某个属性为整个类所共有,不属于任何一个具体对象,其描述类的所有对象共同特征的一个数据项,对于任何对象实例,它的属性值是相同的。
2、类属性定义方法:采用static关键字来声明为静态成员,静态成员包括静态数据成员和静态成员函数。
3、(补充理解概念)实例属性:一个类中所有对象具有的相同的抽象属性。该相同抽象属性是指属性的类型、属性的个数、属性的名称相同,但是各个对象的属性值可以各不相同,这样定义的对象抽象属性在面向对象的方法中称为“实例属性”。
3、以POINT类中建立一个点数记录count为例说明类属性的抽象实现
(1)首先,在设计一个类时我们通常要考虑到类代码的可读性,这就要求我们去对对象之间的关系、对象之间构成的衍生属性、类本身表达的思维逻辑以及代码C++实现的简易程度等因素进行思考和选择(对于此例此处是对点与点之间距离计算分析,用友元函数破拆POINT类的封装使得逻辑关系易读且代码实现简易);
(2)对创建点的个数进行记录,我们便知道count对于每一个此类对象都应该是相同的且随着point的构造而POINT类对象群体同时变化。因此,我们应该考虑用static静态成员来表示它。同时,对于查看这个类属性并不与对象实例相关,我们便可以不通过对象的调用去查看它,而是采用static静态函数去查看它。
(3)类属性是静态属性,实例属性是动态属性。类属性在整个类中只有唯一一个复本,而对于实例属性来说每一个对象都有属于自己的一个副本。静态成员函数可以直接访问该类的静态数据和函数成员,而在静态成员函数中访问非静态成员(即对象实例属性)必须通过对象名。
#include<iostream> #include<iomanip> using namespace std; class POINT { double x, y; static int count; public: POINT(double a, double b) :x(a), y(b) { count++; } POINT(POINT& a) { x = a.x; y = a.y; } ~POINT() {} friend ostream& operator<< (ostream & os, const POINT & a); //操作符的重载,使得点的输出规整美观 friend double JuLi(POINT A,POINT B); //求两点间距离 static int number() { return count; } }; ostream& operator<<(ostream& os, const POINT& a) { os << "(" << a.x << "," << a.y << ")"; return os; } double JuLi(POINT A, POINT B) { return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y)); } int POINT::count = 0; //确保没有构造点时的count值为0 int main() { POINT A(2,1), B(2,6); cout << A << " " << B << endl; cout << "当前创建的点个数为:"<<POINT::number() << endl; cout << JuLi(A, B) << endl; return 0; }
(4)输出结果
1、矩形提取图像(主要代码)
(1)矩形框绘制代码
Point sp(-1, -1); Point ep(-1, -1); Mat orinalimg; void on_draw(int event, int x, int y, int flags,void* userdata) //矩形框定点绘制 { Mat image = *((Mat*)userdata); if (event == EVENT_LBUTTONDOWN) //获取矩形的起始点 { sp.x = x; sp.y = y; } else if (event == EVENT_LBUTTONUP) { ep.x = x; //获取矩形的终点 ep.y = y; int dx = ep.x - sp.x; //获取矩形长宽参数 int dy = ep.y - sp.y; if (dx > 0 && dy > 0) { Rect box(sp.x, sp.y, dx, dy); rectangle(image,box , Scalar(0, 255, 0), 2, 8, 0); //绘制矩形 imshow("图像截取", image); imshow("图像截取区域", image(box)); sp.x = -1; //重置鼠标左键点击的初始点坐标值,达到可多次圈画的目的 sp.y = -1; waitKey(0); //及时释放窗口空间,使得可以多次操作而不造成存储空间指向矛盾冲突 destroyAllWindows(); } } else if (event == EVENT_MOUSEMOVE) { if (sp.x > 0 && sp.y > 0) //必须要鼠标左键按下响应,其点值存在才进行矩形画图操作 { ep.x = x; ep.y = y; int dx = ep.x - sp.x; int dy = ep.y - sp.y; if (dx > 0 && dy > 0) { Rect box(sp.x, sp.y, dx, dy); orinalimg.copyTo(image); //拷贝原图,起到擦除前面多次圈画的目的,只留下最后一次的圈画结果 rectangle(image, box, Scalar(0, 255, 0), 2, 8, 0); imshow("图像截取", image); } } } }
(2)基于图片上的绘制提取
namedWindow("图像截取", WINDOW_AUTOSIZE); setMouseCallback("图像截取", on_draw,(void*)(&image)); imshow("图像截取", image); orinalimg = image.clone(); waitKey(0); destroyAllWindows();
2021年9月25日