一、类的创立目的以及作用
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)输出结果
四、基于opencv的图像矩形提取
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日