C++类的系统思考&对类的一些发散构思应用

一、类的创立目的以及作用

  C++的四大特点是抽象、封装、多态、继承派生。个人理解为抽象是基础,封装和继承派生是方法,多态是工具。

  一般来讲,对一个问题的抽象应该包括两个方面:数据抽象和行为抽象。前者描述某类对象的属性或状态,也就是此类对象区别于彼类对象的特征;后者描述的是某类对象的共同行为或功能特征。

类封装建立目的及作用:通过封装使一部分成员充当类与外部的接口,而将其他成员隐藏起来,这样就达到了对成员访问权限的合理控制,使不同类之间的相互影响减少到最低限度,进而增强了数据的安全性和简化程序编写工作。同时,封装使得代码变得模块化,更加便于维护和运营。

二、类的思维导图

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)输出结果

C++类的系统思考&对类的一些发散构思应用

 四、基于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日

上一篇:C#对串口数据接收、发送的处理


下一篇:对多频外差的改进-校正伽马误差