C++实验二(继承多态)

        目录

         一、继承

二、多态 

三、综合运用


一、继承

  1. 1 继承的概念

     继承的概念:在已有类的基础下创建新的类,新的类可以在保有已有类共性的同时也可实现自身的特性。

  1. 2 基类及派生类

class B : public A;

B类称为子类或派生类

A 类称为父类或基类

派生类中的成员,包含两大部分

  • 一类是从基类继承过来的,一类是自己增加的成员。
  • 从基类继承过过来的表现其共性,而新增的成员体现了其个性。
  1. 3 继承的基本语法

        class 子类:继承方式 父类

  1. 4 继承的三种方式及使用权限
  •  公共继承(public)
  •  保护继承(protected)
  •  私有继承(private)

  • 当对A类进行公共继承时,父类中的公共权限成员到子类B仍为保有公共成员权限,父类中的保护权限成员到子类B仍为保有保护成员权限,而父类中的私有成员子类不能访问到。
  • 当对A类进行保护继承时,父类中的公共权限成员到子类B变为保护权限,父类中的保护权限成员到子类B仍为保护权限,而父类中的私有成员子类不能访问到。
  • 当对A类进行私有继承时,父类中的公共权限成员和保护权限成员到子类B均变为私有权限,而父类中的私有成员子类不能访问到。

 例如:

//继承方式
class A  //父类
{
public:
	int a;
protected:
	int b;
private:
	int c;
};
//1、公共继承 public
class B :public A  //子类的公共继承
{
public:
	void func() //类内访问
	{
		a = 20; //可以拿到父类中的公共权限成员,且到子类中仍是公共权限
		b = 30; //可以拿到父类中的保护权限成员,且到子类中仍是保护权限
		//c = 40; //父类中的私有成员子类不能访问到
	}
};
void publicClass() //类外访问
{
	B b;
	b.a; //其他类只能访问到公共权限
    b.b; //其他类只能访问到公共权限,rotected权限成员访问不到
    b.c; //其他类只能访问到公共权限,private权限成员访问不到
}

//2、保护继承 protected
class C :public A  //子类的保护继承
{
public:
	void func()    //类内访问
	{
		a = 20; //可以访问到父类中的公共权限成员,但到子类中变为保护权限
		b = 30; //可以访问父类中的保护权限成员,且到子类中仍是保护权限
		//c = 40; //会报错!父类中的私有成员子类不能访问到
	}
};
void protectedClass() //类外访问
{
	C c;
	c.a; //由于使用保护继承,成员权限由public变为protected,故访问不到
    c.b; //protected权限成员类外访问不到
    c.c; //private权限成员访问不到
}
//3、私有继承 private
class D :public A  //子类的私有继承
{
public:
	void func() //类内访问
	{
		a = 20; //可以拿到父类中的公共权限成员,但到子类中变为私有权限
		b = 30; //可以拿到父类中的保护权限成员,且到子类中变为私有权限
		//c = 40; //会报错!父类中的私有成员子类不能访问到
	}
};
void privateClass() //类外访问
{
	D d;
    d.a; //由于使用私有继承,成员权限由public变为private,故访问不到
    d.b; //成员权限由protected变为private,类外访问不到
    d.c; //private权限成员类外访问不到
}
  1. 5 继承中的对象模型

父类中私有成员也被子类继承下去了,只是被编译器隐藏而访问不到。

//继承中的对象模型
class Base  //父类
{
public:    //公共权限
	int m_A;     // 4
protected:    //保护权限
	int m_B;    // 4
private:    //私有权限
	int m_C; //私有成员只是被隐藏了,但是还是会继承下去     // 4
};

//公共继承
class Son :public Base
{
public:
	int m_D;    // 4
};

void test01()
{
	cout << "sizeof Son = " << sizeof(Son) << endl;    //结果为16
}

int main() {

	test01();

	system("pause");

	return 0;
}

  1. 6 继承中构造和析构的顺序

子类继承父类后,当创建子类对象时,也会调用父类的构造函数。其调用顺序为:先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反,析构时先调用子类析构函数,再调用父类析构函数。

class Base     //父类
{
public:
	Base()
	{
		cout << "Base父类构造函数!" << endl;
	}
	~Base()
	{
		cout << "Base父类析构函数!" << endl;
	}
};

class Son : public Base    //子类的公共继承
{
public:
	Son()
	{
		cout << "Son子类造函数!" << endl;
	}
	~Son()
	{
		cout << "Son子类析构函数!" << endl;
	}

};


void test01()
{
	//继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
	Son s;
}

  1. 7 继承同名成员处理方式
  • 访问子类同名成员 直接访问即可
  • 访问父类同名成员 需要加作用域
class Base  // 父类
{
public:
	Base()  
	{
		m_A = 100;
	}

	void func()
	{
		cout << "Base - func()调用" << endl;
	}

	void func(int a)
	{
		cout << "Base - func(int a)调用" << endl;
	}

public:
	int m_A;
};


class Son : public Base {      //子类的公共继承
public:
	Son()
	{
		m_A = 200;
	}

	//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
	//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
	void func()
	{
		cout << "Son - func()调用" << endl;
	}
public:
	int m_A;
};

void test01()
{
	Son s;

	cout << "Son下的m_A = " << s.m_A << endl;//父类同名函数被隐藏,调用子类
	cout << "Base下的m_A = " << s.Base::m_A << endl; //父类中的同名成员函数被隐藏,需要加父类的作用域

	s.func();//调用子类构造函数
	s.Base::func();//调用父类的无参构造函数
	s.Base::func(10);//调用父类的有参构造函数

}

总结:

  • 子类对象可以直接访问到子类中同名成员
  • 子类对象加作用域可以访问到父类同名成员
  • 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数。

  1. 8 多继承

C++允许一个类多继承。但多继承可能会引发父类中有同名成员出现,故C++实际开发中不建议使用多继承。多继承中如果父类中出现了同名情况,子类使用时候要加作用域。

多继承语法

多继承语法:class 子类 :继承方式 父类1 , 继承方式 父类2...

菱形继承

菱形继承的概念:​

  • 两个派生类(子类)继承同一个基类(父类)
  • ​ 又有某个类同时继承者两个派生类
class Animal
{
public:
	int m_Age;
};

//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类
class Sheep : virtual public Animal {};
class Tuo   : virtual public Animal {};
class SheepTuo : public Sheep, public Tuo {};

void test01()
{
	SheepTuo st;
	st.Sheep::m_Age = 100;
	st.Tuo::m_Age = 200;

	cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
	cout << "st.Tuo::m_Age = " <<  st.Tuo::m_Age << endl;
	cout << "st.m_Age = " << st.m_Age << endl;
}

总结:

  • 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
  • 利用虚继承可以解决菱形继承问题

二、多态

  1. 多态分类及区别

多态分为两类

  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数实现运行时多态

静态多态和动态多态区别:

  • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址

多态使用条件

  • 父类指针或引用指向子类对象

重写:函数返回值类型 函数名 参数列表 完全一致称为重写

多态满足条件

  • 有继承关系
  • 子类重写父类中的虚函数
  • 父类指针或引用指向子类对象
class Animal
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
};

class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};

class Dog :public Animal
{
public:

	void speak()
	{
		cout << "小狗在说话" << endl;
	}

};
//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编

void DoSpeak(Animal & animal)
{
	animal.speak();
}
//
//多态满足条件: 
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象

void test01()
{
	Cat cat;
	DoSpeak(cat);


	Dog dog;
	DoSpeak(dog);
}


int main() {

	test01();

	system("pause");

	return 0;
}

2 虚函数

  • 冠以关键字 virtual 的成员函数称为虚函数
  • 实现运行时多态的关键首先是要说明虚函数
  • 基类指针调用派生类的不同实现版本
  • 纯虚函数和抽象类

3 纯虚函数与抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容,因此可以将虚函数改为纯虚函数。纯虚函数是一种特殊的虚函数。
在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。
纯虚函数是一个在基类中说明的虚函数,在基类中没有定义, 要求任何派生类都定义自己的版本
纯虚函数为各派生类提供一个公共界面
纯虚函数说明形式:virtual 类型 函数名(参数表)= 0 ;
一个具有纯虚函数的基类称为抽象类。

纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;

抽象类特点

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类

4 虚析构与纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

解决方式:将父类中的析构函数改为虚析构或者纯虚析构

虚析构和纯虚析构共性:

  • 可以解决父类指针释放子类对象
  • 都需要有具体的函数实现

虚析构和纯虚析构区别:

  • 如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法:

virtual ~类名(){}

纯虚析构语法:

virtual ~类名() = 0;

类名::~类名(){}

class Animal {
public:

	Animal()
	{
		cout << "Animal 构造函数调用!" << endl;
	}
	virtual void Speak() = 0;

	//析构函数加上virtual关键字,变成虚析构函数
	//virtual ~Animal()
	//{
	//	cout << "Animal虚析构函数调用!" << endl;
	//}


	virtual ~Animal() = 0;
};

Animal::~Animal()
{
	cout << "Animal 纯虚析构函数调用!" << endl;
}

//和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。

class Cat : public Animal {
public:
	Cat(string name)
	{
		cout << "Cat构造函数调用!" << endl;
		m_Name = new string(name);
	}
	virtual void Speak()
	{
		cout << *m_Name <<  "小猫在说话!" << endl;
	}
	~Cat()
	{
		cout << "Cat析构函数调用!" << endl;
		if (this->m_Name != NULL) {
			delete m_Name;
			m_Name = NULL;
		}
	}

public:
	string *m_Name;
};

void test01()
{
	Animal *animal = new Cat("Tom");
	animal->Speak();

	//通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
	//怎么解决?给基类增加一个虚析构函数
	//虚析构函数就是用来解决通过父类指针释放子类对象
	delete animal;
}

int main() {

	test01();

	system("pause");

	return 0;
}

总结:

​ 1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象

​ 2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构

​ 3. 拥有纯虚析构函数的类也属于抽象类

三、综合运用

代码实现

  1. main.cpp
    #include<vector>
    #include "graphics.h"
    #include<iostream>
    #include "CShape.h"
    using namespace std;
    
    int main()
    {
    	//图形画布基础设置
    	initgraph(640, 480);
    	setbkcolor(WHITE);
    	delay_ms(0);
    	setcolor(BLACK);
    	setfont(20, 0, "楷体");
    	setbkmode(TRANSPARENT);
    	//enter+左击-->新建矩形");
    	//enter+右击-->新建三角形");
    	//enter+滚轮中间-->新建组合图形
    
    	//ctrl+左击-->复制图形");
    	//ctrl+右击-->粘贴图形");
    
    	vector<CShape*>shapes;
    	vector<CShape*>shapestmp;
    
    	shapes.push_back(new CTriangle(CPoint(320, 320), CPoint(250, 340), CPoint(340, 450)));
    	//shapes.push_back(new CTriangle(CPoint(10, 10), CPoint(150, 10), CPoint(150, 150)));
    	shapes.push_back(new CRect(CPoint(200, 200), CPoint(300, 300)));
    	shapes.push_back(new Comgraphics(CRect(CPoint(250, 50))));
    
    
    	//移动
    	bool move_flag = false;
    	bool copy_flag = false;
    	bool redraw = true;
    	//鼠标点击时记录它的坐标
    	int clickX, clickY;
    	int copyX, copyY;
    	int checkedid = -1;
    	int copyid = -1;
    
    	for (; is_run(); delay_fps(60)) {
    		while (mousemsg()) {
    			mouse_msg msg = getmouse();
    
    			//判断鼠标的移动
    			if (msg.is_move()) {
    				if (checkedid != -1) {
    					if (move_flag) {
    						shapes[checkedid]->Move(msg.x - clickX, msg.y - clickY);
    					}
    				}
    				clickX = msg.x;
    				clickY = msg.y;
    				redraw = true;
    			}
    
    			// 判断鼠标左键
    			else if (msg.is_left()) {
    				// 判断鼠标左键是否按下
    				if (msg.is_down()) {
    					clickX = msg.x;
    					clickY = msg.y;
    
    					CPoint pt = CPoint(clickX, clickY);
    					int isIn = 0;
    					for (int i = 0; i < shapes.size(); i++) {
    						if (shapes[i]->ptIn(pt)) {
    							isIn = 1;
    							//如果鼠标在图形区域内就设置移动的flag为true
    							move_flag = true;
    							checkedid = i;
    							redraw = true;
    							break;
    						}
    					}
    					if (isIn == 0)
    						checkedid = -1;
    				}
    				else {
    					move_flag = false;
    				}
    			}
    		}
    		// 重新绘图
    		if (redraw) {
    			redraw = false;
    			cleardevice();
    			for (int i = 0; i < shapes.size(); i++) {
    				if (i == checkedid)
    					shapes[i]->DrawColor();
    				else
    					shapes[i]->Draw();
    			}
    		}
    
    		while (kbmsg()) {
    			key_msg msgk = getkey();
    			if (msgk.key == key_enter && msgk.msg == key_msg_down) {
    				mouse_msg msgm = getmouse();
    				if (msgm.is_left()) {
    					// 判断鼠标左键是否按下
    					if (msgm.is_down()) {
    						shapes.push_back(new CRect(CPoint(msgm.x, msgm.y)));
    						redraw = true;
    					}
    				}
    				if (msgm.is_right()) {
    					// 判断鼠标右键是否按下
    					if (msgm.is_down()) {
    						shapes.push_back(new CTriangle(CPoint(msgm.x, msgm.y)));
    						redraw = true;
    					}
    				}
    				if (msgm.is_mid()) {
    					CRect r1 = CRect(CPoint(msgm.x, msgm.y));
    					// 判断鼠标中键是否按下
    					if (msgm.is_down()) {
    						shapes.push_back(new Comgraphics(r1));
    						redraw = true;
    					}
    				}
    			}
    			if (msgk.key == key_control && msgk.msg == key_msg_down) {
    				mouse_msg msgm = getmouse();
    				if (msgm.is_left()) {
    					// 判断鼠标左键是否按下
    					if (msgm.is_down()) {
    						copyX = msgm.x;
    						copyY = msgm.y;
    						CPoint pt = CPoint(copyX, copyY);
    						for (int i = 0; i < shapes.size(); i++) {
    							if (shapes[i]->ptIn(pt)) {
    								//如果鼠标在图形区域内就设置移动的flag为true
    								copy_flag = true;
    								copyid = i;
    								break;
    							}
    						}
    					}
    				}
    				if (msgm.is_right()) {
    					// 判断鼠标右键是否按下
    					if (msgm.is_down()) {
    						if (copy_flag == true) {
    							shapes.push_back(&(shapes[copyid]->Clone())->Move(msgm.x - copyX, msgm.y - copyY));
    							redraw = true;
    						}
    					}
    				}
    
    			}
    		}
    	}
    	closegraph();
    	return 0;
    }
    
    

  2. CShape.cpp
    #include "CShape.h"
    #include "graphics.h"
    #include <iostream>
    using namespace std;
    //CShape
    CShape::CShape()
    {
    }
    CShape::CShape(const CShape& shape) {
    	m_sName = shape.m_sName;
    }
    CShape::~CShape()
    {
    }
    double CShape::GetArea() const {
    	return 0;
    }
    bool CShape::ptIn(const CPoint& pt) const {
    	return false;
    }
    bool CShape::InRect(const CRect& rc) const {
    	return false;
    }
    void CShape::Draw() const
    {
    }
    void CShape::DrawColor()
    {
    }
    CShape* CShape::Clone() const {
    	return new CShape(*this);
    }
    CShape& CShape::Move(int nOffsetX, int nOffsetY) {
    	return *this;
    }
    
    //CPoint
    CPoint::CPoint(int nPosX, int nPosY) {
    	m_nPosX = nPosX;
    	m_nPosY = nPosY;
    }
    CPoint::CPoint(const CPoint& pt) {
    	m_nPosX = pt.m_nPosX;
    	m_nPosY = pt.m_nPosY;
    }
    CPoint::~CPoint() {
    	//cout << "CPoint::~CPoint()\n";
    }
    double CPoint::GetArea() const {
    	return 0;
    }
    bool CPoint::ptIn(const CPoint& pt) const {
    	return false;
    }
    bool CPoint::InRect(const CRect& rc) const {
    	return rc.ptIn(*this);
    }
    void CPoint::Draw() const {
    	circle(m_nPosX, m_nPosY, 2);
    }
    void CPoint::DrawColor()
    {
    }
    CPoint* CPoint::Clone() const {
    	return new CPoint(*this);
    }
    CPoint& CPoint::Move(int nOffsetX, int nOffsetY) {
    	m_nPosX += nOffsetX;
    	m_nPosY += nOffsetY;
    	return *this;
    }
    
    //CTriangle
    CTriangle::CTriangle(const CTriangle& tri) {
    	for (int i = 0; i < 3; i++) {
    		m_pts[i] = tri.m_pts[i];
    	}
    }
    CTriangle::~CTriangle() {
    	//cout << "CTriangle::~CTriangle()\n";
    }
    CTriangle::CTriangle(const CPoint& pt1, const CPoint& pt2, const CPoint& pt3) {
    	m_pts[0] = pt1;
    	m_pts[1] = pt2;
    	m_pts[2] = pt3;
    }
    CTriangle::CTriangle(const CPoint& pt)
    {
    	CPoint* pt1 = new CPoint(pt.m_nPosX + 100, pt.m_nPosY + 90);
    	CPoint* pt2 = new CPoint(pt.m_nPosX, pt.m_nPosY + 90);
    	m_pts[0] = pt;
    	m_pts[1] = *pt1;
    	m_pts[2] = *pt2;
    }
    
    CShape& CTriangle::Move(int nOffsetX, int nOffsetY) {
    	for (int i = 0; i < 3; i++) {
    		m_pts[i].Move(nOffsetX, nOffsetY);
    	}
    	return *this;
    }
    double CTriangle::GetArea() const {
    	int x1, y1, x2, y2, x3, y3;
    	x1 = m_pts[0].m_nPosX;
    	y1 = m_pts[0].m_nPosY;
    	x2 = m_pts[1].m_nPosX;
    	y2 = m_pts[1].m_nPosY;
    	x3 = m_pts[2].m_nPosX;
    	y3 = m_pts[2].m_nPosY;
    
    	double bottomLine = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
    	double verticalLine1 = abs((y1 - y2) * x3 - (x1 - x2) * y3 + (x1 - x2) * y2 - (y1 - y2) * x2);
    	double verticalLine2 = sqrt(pow(y1 - y2, 2) + pow(x1 - x2, 2));
    	double verticalLine = verticalLine1 / verticalLine2;
    
    	return (verticalLine * bottomLine) / 2.0;
    }
    bool CTriangle::ptIn(const CPoint& pt) const {
    	CTriangle c1 = CTriangle(m_pts[0], m_pts[1], pt);
    	CTriangle c2 = CTriangle(m_pts[1], m_pts[2], pt);
    	CTriangle c3 = CTriangle(m_pts[2], m_pts[0], pt);
    
    	double totalArea = c1.GetArea() + c2.GetArea() + c3.GetArea();
    
    	if (totalArea == this->GetArea())
    		return true;
    	else
    		return false;
    }
    bool CTriangle::InRect(const CRect& rc) const {
    	return rc.ptIn(m_pts[0]) && rc.ptIn(m_pts[1]) && rc.ptIn(m_pts[2]);
    }
    void CTriangle::Draw() const {
    	int poly[8] = { m_pts[0].m_nPosX ,m_pts[0].m_nPosY,m_pts[1].m_nPosX,m_pts[1].m_nPosY,
    				m_pts[2].m_nPosX,m_pts[2].m_nPosY, m_pts[0].m_nPosX ,m_pts[0].m_nPosY };
    	setfillcolor(EGERGB(0xFF, 0xFF, 0xFF));
    	fillpoly(4, poly);
    }
    void CTriangle::DrawColor() {
    	int poly[8] = { m_pts[0].m_nPosX ,m_pts[0].m_nPosY,m_pts[1].m_nPosX,m_pts[1].m_nPosY,
    				m_pts[2].m_nPosX,m_pts[2].m_nPosY, m_pts[0].m_nPosX ,m_pts[0].m_nPosY };
    	setfillcolor(EGERGB(0xFF, 0xA5, 0x00));
    	fillpoly(4, poly);
    }
    CShape* CTriangle::Clone() const {
    	return new CTriangle(*this);
    }
    
    //CRect
    CRect::CRect(CPoint pt1, CPoint pt2) {
    	m_ptLT = CPoint(min(pt1.m_nPosX, pt2.m_nPosX), min(pt1.m_nPosY, pt2.m_nPosY));
    	m_ptBR = CPoint(max(pt1.m_nPosX, pt2.m_nPosX), max(pt1.m_nPosY, pt2.m_nPosY));
    }
    CRect::CRect(const CRect& rc) {
    	m_ptLT = rc.m_ptLT;
    	m_ptBR = rc.m_ptBR;
    }
    CRect::CRect(CPoint pt1)
    {
    	m_ptLT = CPoint(pt1.m_nPosX, pt1.m_nPosY);
    	m_ptBR = CPoint(pt1.m_nPosX + 100, pt1.m_nPosY + 100);
    }
    CRect::~CRect() {
    	// cout << "CRect::CRect()\n";
    }
    double CRect::GetArea() const {
    	return (m_ptBR.m_nPosX - m_ptLT.m_nPosX) * (m_ptBR.m_nPosY - m_ptLT.m_nPosY);
    }
    bool CRect::ptIn(const CPoint& pt) const {
    	return (pt.m_nPosX >= m_ptLT.m_nPosX && pt.m_nPosX <= m_ptBR.m_nPosX) &&
    		(pt.m_nPosY >= m_ptLT.m_nPosY && pt.m_nPosY <= m_ptBR.m_nPosY);
    }
    bool CRect::InRect(const CRect& rc) const {
    	return rc.ptIn(m_ptLT) && rc.ptIn(m_ptBR);
    }
    void CRect::Draw() const {
    	// 存储n个顶点的x,y坐标
    	int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY,
    	m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY };
    	// 绘制n个顶点的多边形,第一个参数必须要传入n+1,pts最后一个顶点坐标和第一个相同
    	//drawpoly(5, pts);
    	setfillcolor(EGERGB(0xFF, 0xFF, 0xFF));
    	fillpoly(5, pts);
    }
    void CRect::DrawColor() {
    	int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY,
    	m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY };
    	// 绘制n个顶点的多边形,第一个参数必须要传入n+1,pts最后一个顶点坐标和第一个相同
    	setfillcolor(EGERGB(0xFF, 0xA5, 0x00));
    	fillpoly(5, pts);
    }
    CShape* CRect::Clone() const {
    	return new CRect(*this);
    }
    CShape& CRect::Move(int nOffsetX, int nOffsetY) {
    	m_ptLT.Move(nOffsetX, nOffsetY);
    	m_ptBR.Move(nOffsetX, nOffsetY);
    	return *this;
    
    }
    //Comgraphics
    Comgraphics::Comgraphics(const CRect& pt1) {
    
    	m_pt1.m_nPosX = pt1.m_ptBR.m_nPosX;
    	m_pt1.m_nPosY = pt1.m_ptLT.m_nPosY + (pt1.m_ptBR.m_nPosY - pt1.m_ptLT.m_nPosY) / 2;
    	m_pt2.m_nPosX = pt1.m_ptLT.m_nPosX + (pt1.m_ptBR.m_nPosX - pt1.m_ptLT.m_nPosX) / 2;
    	m_pt2.m_nPosY = pt1.m_ptBR.m_nPosY;
    	m_ptLT = pt1.m_ptLT;
    	m_ptBR = pt1.m_ptBR;
    
    }
    Comgraphics::Comgraphics(const Comgraphics& rc) {
    	m_pt1 = rc.m_pt1;
    	m_pt2 = rc.m_pt2;
    	m_ptBR = rc.m_ptBR;
    	m_ptLT = rc.m_ptLT;
    }
    Comgraphics::Comgraphics(const CPoint pt1) {
    	m_ptLT = CPoint(pt1.m_nPosX, pt1.m_nPosY);
    	m_ptBR = CPoint(pt1.m_nPosX + 60, pt1.m_nPosY + 80);
    }
    Comgraphics::~Comgraphics() {
    	cout << "Comgraphics::~Comgraphics()" << endl;
    
    }
    double Comgraphics::GetArea()  const {
    	return 0.0;
    }
    bool Comgraphics::ptIn(const CPoint& pt) const {
    	return (pt.m_nPosX >= m_ptLT.m_nPosX && pt.m_nPosX <= m_ptBR.m_nPosX) &&
    		(pt.m_nPosY >= m_ptLT.m_nPosY && pt.m_nPosY <= m_ptBR.m_nPosY);
    }
    bool Comgraphics::InRect(const CRect& rc) const const {
    	return rc.ptIn(m_ptLT) && rc.ptIn(m_ptBR);
    }
    void Comgraphics::Draw() const {
    	// 存储n个顶点的x,y坐标
    	int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY,
    	m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY };
    	// 绘制n个顶点的多边形,第一个参数必须要传入n+1,pts最后一个顶点坐标和第一个相同
    	//drawpoly(5, pts);
    	setfillcolor(GREEN);
    	fillpoly(5, pts);
    	line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY);
    	line(m_ptLT.m_nPosX, m_ptLT.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY);
    	line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_ptLT.m_nPosX, m_ptLT.m_nPosY);
    }
    void Comgraphics::DrawColor() {
    	// 存储n个顶点的x,y坐标
    	int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY,
    	m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY };
    	// 绘制n个顶点的多边形,第一个参数必须要传入n+1,pts最后一个顶点坐标和第一个相同
    	setfillcolor(YELLOW);
    	fillpoly(5, pts);
    	line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY);
    	line(m_ptLT.m_nPosX, m_ptLT.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY);
    	line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_ptLT.m_nPosX, m_ptLT.m_nPosY);
    }
    CShape* Comgraphics::Clone() const {
    	return new Comgraphics(*(this));
    }
    
    CShape& Comgraphics::Move(int nOffsetX, int nOffsetY) {
    	m_ptLT.Move(nOffsetX, nOffsetY);
    	m_ptBR.Move(nOffsetX, nOffsetY);
    	m_pt1.Move(nOffsetX, nOffsetY);
    	m_pt2.Move(nOffsetX, nOffsetY);
    	return *this;
    }
    
    

  3. CShape.h
    #include "CShape.h"
    #include "graphics.h"
    #include <iostream>
    using namespace std;
    //CShape
    CShape::CShape()
    {
    }
    CShape::CShape(const CShape& shape) {
    	m_sName = shape.m_sName;
    }
    CShape::~CShape()
    {
    }
    double CShape::GetArea() const {
    	return 0;
    }
    bool CShape::ptIn(const CPoint& pt) const {
    	return false;
    }
    bool CShape::InRect(const CRect& rc) const {
    	return false;
    }
    void CShape::Draw() const
    {
    }
    void CShape::DrawColor()
    {
    }
    CShape* CShape::Clone() const {
    	return new CShape(*this);
    }
    CShape& CShape::Move(int nOffsetX, int nOffsetY) {
    	return *this;
    }
    
    //CPoint
    CPoint::CPoint(int nPosX, int nPosY) {
    	m_nPosX = nPosX;
    	m_nPosY = nPosY;
    }
    CPoint::CPoint(const CPoint& pt) {
    	m_nPosX = pt.m_nPosX;
    	m_nPosY = pt.m_nPosY;
    }
    CPoint::~CPoint() {
    	//cout << "CPoint::~CPoint()\n";
    }
    double CPoint::GetArea() const {
    	return 0;
    }
    bool CPoint::ptIn(const CPoint& pt) const {
    	return false;
    }
    bool CPoint::InRect(const CRect& rc) const {
    	return rc.ptIn(*this);
    }
    void CPoint::Draw() const {
    	circle(m_nPosX, m_nPosY, 2);
    }
    void CPoint::DrawColor()
    {
    }
    CPoint* CPoint::Clone() const {
    	return new CPoint(*this);
    }
    CPoint& CPoint::Move(int nOffsetX, int nOffsetY) {
    	m_nPosX += nOffsetX;
    	m_nPosY += nOffsetY;
    	return *this;
    }
    
    //CTriangle
    CTriangle::CTriangle(const CTriangle& tri) {
    	for (int i = 0; i < 3; i++) {
    		m_pts[i] = tri.m_pts[i];
    	}
    }
    CTriangle::~CTriangle() {
    	//cout << "CTriangle::~CTriangle()\n";
    }
    CTriangle::CTriangle(const CPoint& pt1, const CPoint& pt2, const CPoint& pt3) {
    	m_pts[0] = pt1;
    	m_pts[1] = pt2;
    	m_pts[2] = pt3;
    }
    CTriangle::CTriangle(const CPoint& pt)
    {
    	CPoint* pt1 = new CPoint(pt.m_nPosX + 100, pt.m_nPosY + 90);
    	CPoint* pt2 = new CPoint(pt.m_nPosX, pt.m_nPosY + 90);
    	m_pts[0] = pt;
    	m_pts[1] = *pt1;
    	m_pts[2] = *pt2;
    }
    
    CShape& CTriangle::Move(int nOffsetX, int nOffsetY) {
    	for (int i = 0; i < 3; i++) {
    		m_pts[i].Move(nOffsetX, nOffsetY);
    	}
    	return *this;
    }
    double CTriangle::GetArea() const {
    	int x1, y1, x2, y2, x3, y3;
    	x1 = m_pts[0].m_nPosX;
    	y1 = m_pts[0].m_nPosY;
    	x2 = m_pts[1].m_nPosX;
    	y2 = m_pts[1].m_nPosY;
    	x3 = m_pts[2].m_nPosX;
    	y3 = m_pts[2].m_nPosY;
    
    	double bottomLine = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
    	double verticalLine1 = abs((y1 - y2) * x3 - (x1 - x2) * y3 + (x1 - x2) * y2 - (y1 - y2) * x2);
    	double verticalLine2 = sqrt(pow(y1 - y2, 2) + pow(x1 - x2, 2));
    	double verticalLine = verticalLine1 / verticalLine2;
    
    	return (verticalLine * bottomLine) / 2.0;
    }
    bool CTriangle::ptIn(const CPoint& pt) const {
    	CTriangle c1 = CTriangle(m_pts[0], m_pts[1], pt);
    	CTriangle c2 = CTriangle(m_pts[1], m_pts[2], pt);
    	CTriangle c3 = CTriangle(m_pts[2], m_pts[0], pt);
    
    	double totalArea = c1.GetArea() + c2.GetArea() + c3.GetArea();
    
    	if (totalArea == this->GetArea())
    		return true;
    	else
    		return false;
    }
    bool CTriangle::InRect(const CRect& rc) const {
    	return rc.ptIn(m_pts[0]) && rc.ptIn(m_pts[1]) && rc.ptIn(m_pts[2]);
    }
    void CTriangle::Draw() const {
    	int poly[8] = { m_pts[0].m_nPosX ,m_pts[0].m_nPosY,m_pts[1].m_nPosX,m_pts[1].m_nPosY,
    				m_pts[2].m_nPosX,m_pts[2].m_nPosY, m_pts[0].m_nPosX ,m_pts[0].m_nPosY };
    	setfillcolor(EGERGB(0xFF, 0xFF, 0xFF));
    	fillpoly(4, poly);
    }
    void CTriangle::DrawColor() {
    	int poly[8] = { m_pts[0].m_nPosX ,m_pts[0].m_nPosY,m_pts[1].m_nPosX,m_pts[1].m_nPosY,
    				m_pts[2].m_nPosX,m_pts[2].m_nPosY, m_pts[0].m_nPosX ,m_pts[0].m_nPosY };
    	setfillcolor(EGERGB(0xFF, 0xA5, 0x00));
    	fillpoly(4, poly);
    }
    CShape* CTriangle::Clone() const {
    	return new CTriangle(*this);
    }
    
    //CRect
    CRect::CRect(CPoint pt1, CPoint pt2) {
    	m_ptLT = CPoint(min(pt1.m_nPosX, pt2.m_nPosX), min(pt1.m_nPosY, pt2.m_nPosY));
    	m_ptBR = CPoint(max(pt1.m_nPosX, pt2.m_nPosX), max(pt1.m_nPosY, pt2.m_nPosY));
    }
    CRect::CRect(const CRect& rc) {
    	m_ptLT = rc.m_ptLT;
    	m_ptBR = rc.m_ptBR;
    }
    CRect::CRect(CPoint pt1)
    {
    	m_ptLT = CPoint(pt1.m_nPosX, pt1.m_nPosY);
    	m_ptBR = CPoint(pt1.m_nPosX + 100, pt1.m_nPosY + 100);
    }
    CRect::~CRect() {
    	// cout << "CRect::CRect()\n";
    }
    double CRect::GetArea() const {
    	return (m_ptBR.m_nPosX - m_ptLT.m_nPosX) * (m_ptBR.m_nPosY - m_ptLT.m_nPosY);
    }
    bool CRect::ptIn(const CPoint& pt) const {
    	return (pt.m_nPosX >= m_ptLT.m_nPosX && pt.m_nPosX <= m_ptBR.m_nPosX) &&
    		(pt.m_nPosY >= m_ptLT.m_nPosY && pt.m_nPosY <= m_ptBR.m_nPosY);
    }
    bool CRect::InRect(const CRect& rc) const {
    	return rc.ptIn(m_ptLT) && rc.ptIn(m_ptBR);
    }
    void CRect::Draw() const {
    	// 存储n个顶点的x,y坐标
    	int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY,
    	m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY };
    	// 绘制n个顶点的多边形,第一个参数必须要传入n+1,pts最后一个顶点坐标和第一个相同
    	//drawpoly(5, pts);
    	setfillcolor(EGERGB(0xFF, 0xFF, 0xFF));
    	fillpoly(5, pts);
    }
    void CRect::DrawColor() {
    	int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY,
    	m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY };
    	// 绘制n个顶点的多边形,第一个参数必须要传入n+1,pts最后一个顶点坐标和第一个相同
    	setfillcolor(EGERGB(0xFF, 0xA5, 0x00));
    	fillpoly(5, pts);
    }
    CShape* CRect::Clone() const {
    	return new CRect(*this);
    }
    CShape& CRect::Move(int nOffsetX, int nOffsetY) {
    	m_ptLT.Move(nOffsetX, nOffsetY);
    	m_ptBR.Move(nOffsetX, nOffsetY);
    	return *this;
    
    }
    //Comgraphics
    Comgraphics::Comgraphics(const CRect& pt1) {
    
    	m_pt1.m_nPosX = pt1.m_ptBR.m_nPosX;
    	m_pt1.m_nPosY = pt1.m_ptLT.m_nPosY + (pt1.m_ptBR.m_nPosY - pt1.m_ptLT.m_nPosY) / 2;
    	m_pt2.m_nPosX = pt1.m_ptLT.m_nPosX + (pt1.m_ptBR.m_nPosX - pt1.m_ptLT.m_nPosX) / 2;
    	m_pt2.m_nPosY = pt1.m_ptBR.m_nPosY;
    	m_ptLT = pt1.m_ptLT;
    	m_ptBR = pt1.m_ptBR;
    
    }
    Comgraphics::Comgraphics(const Comgraphics& rc) {
    	m_pt1 = rc.m_pt1;
    	m_pt2 = rc.m_pt2;
    	m_ptBR = rc.m_ptBR;
    	m_ptLT = rc.m_ptLT;
    }
    Comgraphics::Comgraphics(const CPoint pt1) {
    	m_ptLT = CPoint(pt1.m_nPosX, pt1.m_nPosY);
    	m_ptBR = CPoint(pt1.m_nPosX + 60, pt1.m_nPosY + 80);
    }
    Comgraphics::~Comgraphics() {
    	cout << "Comgraphics::~Comgraphics()" << endl;
    
    }
    double Comgraphics::GetArea()  const {
    	return 0.0;
    }
    bool Comgraphics::ptIn(const CPoint& pt) const {
    	return (pt.m_nPosX >= m_ptLT.m_nPosX && pt.m_nPosX <= m_ptBR.m_nPosX) &&
    		(pt.m_nPosY >= m_ptLT.m_nPosY && pt.m_nPosY <= m_ptBR.m_nPosY);
    }
    bool Comgraphics::InRect(const CRect& rc) const const {
    	return rc.ptIn(m_ptLT) && rc.ptIn(m_ptBR);
    }
    void Comgraphics::Draw() const {
    	// 存储n个顶点的x,y坐标
    	int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY,
    	m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY };
    	// 绘制n个顶点的多边形,第一个参数必须要传入n+1,pts最后一个顶点坐标和第一个相同
    	//drawpoly(5, pts);
    	setfillcolor(GREEN);
    	fillpoly(5, pts);
    	line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY);
    	line(m_ptLT.m_nPosX, m_ptLT.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY);
    	line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_ptLT.m_nPosX, m_ptLT.m_nPosY);
    }
    void Comgraphics::DrawColor() {
    	// 存储n个顶点的x,y坐标
    	int pts[10] = { m_ptLT.m_nPosX,m_ptLT.m_nPosY,m_ptBR.m_nPosX,m_ptLT.m_nPosY,
    	m_ptBR.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptBR.m_nPosY,m_ptLT.m_nPosX,m_ptLT.m_nPosY };
    	// 绘制n个顶点的多边形,第一个参数必须要传入n+1,pts最后一个顶点坐标和第一个相同
    	setfillcolor(YELLOW);
    	fillpoly(5, pts);
    	line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY);
    	line(m_ptLT.m_nPosX, m_ptLT.m_nPosY, m_pt2.m_nPosX, m_pt2.m_nPosY);
    	line(m_pt1.m_nPosX, m_pt1.m_nPosY, m_ptLT.m_nPosX, m_ptLT.m_nPosY);
    }
    CShape* Comgraphics::Clone() const {
    	return new Comgraphics(*(this));
    }
    
    CShape& Comgraphics::Move(int nOffsetX, int nOffsetY) {
    	m_ptLT.Move(nOffsetX, nOffsetY);
    	m_ptBR.Move(nOffsetX, nOffsetY);
    	m_pt1.Move(nOffsetX, nOffsetY);
    	m_pt2.Move(nOffsetX, nOffsetY);
    	return *this;
    }
    
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值