目录
一、继承
- 1 继承的概念
继承的概念:在已有类的基础下创建新的类,新的类可以在保有已有类共性的同时也可实现自身的特性。
- 2 基类及派生类
class B : public A;
B类称为子类或派生类
A 类称为父类或基类
派生类中的成员,包含两大部分:
- 一类是从基类继承过来的,一类是自己增加的成员。
- 从基类继承过过来的表现其共性,而新增的成员体现了其个性。
- 3 继承的基本语法
class 子类:继承方式 父类
- 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权限成员类外访问不到
}
- 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;
}
- 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;
}
- 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);//调用父类的有参构造函数
}
总结:
- 子类对象可以直接访问到子类中同名成员
- 子类对象加作用域可以访问到父类同名成员
- 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数。
- 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;
}
总结:
- 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
- 利用虚继承可以解决菱形继承问题
二、多态
- 多态分类及区别
多态分为两类
- 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
- 动态多态: 派生类和虚函数实现运行时多态
静态多态和动态多态区别:
- 静态多态的函数地址早绑定 - 编译阶段确定函数地址
- 动态多态的函数地址晚绑定 - 运行阶段确定函数地址
多态使用条件
- 父类指针或引用指向子类对象
重写:函数返回值类型 函数名 参数列表 完全一致称为重写
多态满足条件
- 有继承关系
- 子类重写父类中的虚函数
- 父类指针或引用指向子类对象
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. 拥有纯虚析构函数的类也属于抽象类
三、综合运用
代码实现
- 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; }
- 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; }
- 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; }