C++继承和多态


类的继承

一、继承访问权限测试

Grandpa.h

#ifndef GRANDPA_H
#define GRANDPA_H
#include<iostream>
using namespace std;
class Grandpa
{
public:
    void initGrandpa(string name="",int age=0,string id="")  //初始化对象
    {
        this->name=name;
        this->age=age;
        this->id=id;
    };
    string getName() const  //获取private里的name
    {
        return name;
    };
    int getAge()        //获取private里的age
    {
        return age;
    };
    string getId() const    //获取private里的id
    {
        return id;
    };
    void improveDeposit(int improvement)    //改变protected里的deposit
    {
        deposit+=improvement;
    }
    void setDeposit(int deposit)    //设置deposit
    {
        this->deposit=deposit;
    };
    int getDeposit()    //获取protected里的deposit
    {
        return deposit;
    };
private:
    string name;
    int age;
    string id;
protected:
    int deposit;
};



#endif // GRANDPA_H

Father.h

#ifndef GRANDMA_H
#define GRANDMA_H
#include "Grandpa.h"
class Father:protected Grandpa    //继承方式
{
public:
    void initFather(string f_name,int f_age,string f_id,string name,int age,string id)    //初始化father对象,同时调用基类方法初始化从基类继承的name,age属性
    {
        initGrandpa(name,age,id);
        this->f_name=f_name;
        this->f_age=f_age;
        this->f_id=f_id;
    };

    string getName() const  //调用从基类继承的方法获取name
    {
        return Grandpa::getName();
    };
    string getId() const    //调用从基类继承的方法获取id
    {
        return Grandpa::getId();
    };
    int getAge()    //调用从基类继承的方法获取age
    {
        return Grandpa::getAge();
    };
    string getFName() const     //获取此派生类的f_name
    {
        return f_name;
    };
    int getFAge()   //获取此派生类的f_age
    {
        return f_age;
    };
    string getFId() const   //获取此派生类的f_id
    {
        return f_id;
    };
    void setFDeposit(int f_deposit)     //改变此派生类的f_deposit
    {
        this->f_deposit=f_deposit;
    };
    int getFDeposit()   //获取此派生类的f_deposit
    {
        return f_deposit;
    }
    void improveDeposit(int improvement)    //调用从基类继承的方法改变继承的来的deposit属性
    {
        Grandpa::improveDeposit(improvement);
    };
    void improveFDeposit(int improvement)
    {
        f_deposit+=improvement;
    };

private:

    string f_name;
    int f_age;
    string f_id;
protected:
    int f_deposit;
    
};



#endif // GRANDMA_H

main.cpp

#include <iostream>
#include <stdio.h>
#include "Father.h"
 using namespace std;
 int main() {


    Grandpa ga;
    ga.initGrandpa("grandpa",55,"35080");
    cout<<"grandpa:"<<ga.getName()<<",,,"<<ga.getAge()<<",,,"<<ga.getId()<<endl;
    ga.setDeposit(2000);        //grandpa的deposit设置为2000
    cout<<"deposit:"<<ga.getDeposit()<<endl;
    ga.improveDeposit(100);         //grandpa的deposit+100
    cout<<"improve_deposit:"<<ga.getDeposit()<<endl;

    //private继承
//    Father fa;
//    fa.initFather("father",30,"35080","grandpa",55,"35081");
//    cout<<"father:"<<fa.getFName()<<",,,"<<fa.getFAge()<<"..."<<fa.getFId()<<"..."<<fa.getName()<<",,,"<<fa.getAge()<<"..."<<fa.getId()<<endl;
//    fa.setFDeposit(3000);       //father的f_deposit为3000
//    cout<<"f_deposit"<<fa.getFDeposit()<<endl;
//    fa.improveDeposit(200);     //给grandpa的deposit+200,失败
//    fa.improveFDeposit(300);    //给father的deposit+300
//    cout<<"deposit"<<ga.getDeposit()<<"...f_deposit"<<fa.getFDeposit()<<endl;

    //public继承
//    Father fa;
//    fa.initFather("father",30,"35080","grandpa",55,"35081");
//    cout<<"father:"<<fa.getFName()<<",,,"<<fa.getFAge()<<"..."<<fa.getFId()<<"..."<<fa.getName()<<",,,"<<fa.getAge()<<"..."<<fa.getId()<<endl;
//    fa.setFDeposit(3000);       //father的f_deposit为3000
//    cout<<"f_deposit"<<fa.getFDeposit()<<endl;
//    fa.improveDeposit(200);     //给grandpa的deposit+200,失败
//    fa.improveFDeposit(300);    //给father的deposit+300
//    cout<<"deposit"<<ga.getDeposit()<<"...f_deposit"<<fa.getFDeposit()<<endl;

    //protected继承
//    Father fa;
//    fa.initFather("father",30,"35080","grandpa",55,"35081");
//    cout<<"father:"<<fa.getFName()<<",,,"<<fa.getFAge()<<"..."<<fa.getFId()<<"..."<<fa.getName()<<",,,"<<fa.getAge()<<"..."<<fa.getId()<<endl;
//    fa.setFDeposit(3000);       //father的f_deposit为3000
//    cout<<"f_deposit"<<fa.getFDeposit()<<endl;
//    fa.improveDeposit(200);     //给grandpa的deposit+200,失败
//    fa.improveFDeposit(300);    //给father的deposit+300
//    cout<<"deposit"<<ga.getDeposit()<<"...f_deposit"<<fa.getFDeposit()<<endl;
    

    return 0;
 }

测试截图(public、protected、private继承后使用派生类的public方法的结果都相同)
继承方式

fa.improveDeposit(200);     //给继承自grandpa的deposit+200

这个函数的作用是调用继承自基类public中的improveDeposit方法,使继承自基类private里的deposit+200。这个方法执行成功但是deposit的值为200侧面反映了基类的private方法和变量被继承后对于派生类来说不可见,既然不可见,当然也不能更改了,更改的值始终只能是继承后的deposit的值。
派生类新增的protected和private方法和变量不能在外部直接访问,需要调用public里的方法访问,public里的变量则在外部就能访问。派生类继承自基类的方法和变量则根据其在基类中的定义及继承的方式而改变,参照下表:
继承
在外部测试中,除了public继承的基类的public方法和变量可以调用外,其余继承方式及基类中方法和变量都需要在派生类中的public部分定义方法来访问。
在Father类private继承Grandpa类后,原本Grandpa中protected的方法和变量变为派生类的private成员,如果要提升为public,则可以使用using声明引入Grandpa的方法和变量。

using Grandpa::getDeposit;

其实要达成这个方法的效果还有一种,即在派生类Father中调用Grandpa的方法,代码如下

int getDeposit()
    {
//        return deposit;
        return Grandpa::getDeposit();
    };

二、友元类继承测试

main.cpp

#include <iostream>
#include <stdio.h>
#include "Father.h"
 using namespace std;
 int main() {
 	Grandpa ga;
    ga.initGrandpa("grandpa",55,"35080");
    cout<<"grandpa:"<<ga.getName()<<",,,"<<ga.getAge()<<",,,"<<ga.getId()<<endl;
    ga.setDeposit(2000);        //grandpa的deposit设置为2000
    cout<<"deposit:"<<ga.getDeposit()<<endl;
    ga.improveDeposit(100);         //grandpa的deposit+100
    cout<<"improve_deposit:"<<ga.getDeposit()<<endl;
    
	Grandson gs;
	gs.initGrandson("grandson",6,"35082");
	ga.memberCall();
	gs.friendShow();
	gs.friendVisit(ga);
	return 0;
 }

测试截图
友元类

可以看到,当将Grandson定义为Grandpa的友元类后,可以实现Grandson对象gs对Grandpa成员函数的内部调用、Grandson的对象gs对友元类Grandpa的成员函数的访问。


代码截图
void Grandson::friendVisitDerived(Father fa)
{
    cout<<fa.name;      //报错,grandson无法访问father里继承得来的name
    cout<<fa.getName(); //但是可以访问father的public方法
    cout<<fa.f_name;    //报错,grandson无法访问father的private变量f_name
};

在grandson内无法访问派生类father的私有变量f_name及继承得来的name,但是可以访问father的public方法。


代码截图
    void friendVisitDerivedSecond(Grandpa data)
    {
        data.name;          //友元类grandson的派生类daughter访问不了基类grandpa的private变量
        data.getName();     //但可以访问其public方法
    };
    

友元类grandson的派生类daughter访问不了基类grandpa的private变量,但可以访问其public方法。

    void FriendVisitDerivedThird(Father fa)
    {
        fa.f_name;      //友元类的grandson的派生类daughter访问不了基类grandpa的派生类的private变量
        fa.name;        //也访问不了其继承自grandpa的变量
        fa.getName();   //但是可以访问其public的方法
        fa.getFName();
    }

友元类的grandson的派生类daughter访问不了基类grandpa的派生类的private变量,也访问不了其继承自grandpa的变量,但是可以访问其public的方法。

多态性综合应用

polymorphism.h

#ifndef POLYMORPHISM_H
#define POLYMORPHISM_H
#include<iostream>
#include<stdlib.h>
using namespace std;
class dot       //点类
{
public:
    dot(double x,double y)
    {
        this->x=x;
        this->y=y;
    };
    virtual ~dot()
    {
        cout<<"dot release"<<endl;
    };
    virtual void move(double a,double b)      //移动点坐标,以变量的方式
    {
        x=x+a;
        y=y+b;
    };
    double getX()
    {
        return x;
    };
    double getY()
    {
        return y;
    };
    void showDot()
    {
        cout<<"class dot:\n"<<"x:"<<x<<"\ty:"<<y<<endl;
    };
private:
    double x;
    double y;
};


class rectangle:public dot
{
public:
    rectangle(double x,double y):dot(x,y)   //基类的构造函数不能被继承,需要在派生类中显式调用
    {
        this->w=0;
        this->h=0;
    };
    ~rectangle()
    {
        cout<<"rectangle release"<<endl;
    };
    void move(double a, double b) override        //重写rectangle的移动点坐标move,以变量形式
    {
        dot::move(a,b);
        cout<<"rectangle move\n";
    };

    double getW()
    {
        return w;
    };
    double getH()
    {
        return h;
    };


private:
    double w;
    double h;
};

class circle:public dot
{
public:
    circle(double x,double y,double r):dot(x,y)
    {
        this->r=r;
    };
    ~circle()
    {
        cout<<"circle release"<<endl;
    };
    void move(double a,double b) override
    {
        dot::move(a,b);
        cout<<"circle move\n";
    };
    double getR()
    {
        return r;
    };
private:
    double r;
};

class triangle:public dot
{
public:
    triangle(double x,double y):dot(x,y)
    {
        ;
    };
    ~triangle()
    {
        cout<<"triangle release"<<endl;
    };
    void move(double a,double b) override
    {
        dot::move(a,b);
        cout<<"triangle move\n";
    };
};

#endif // POLYMORPHISM_H

main.cpp

dot aDot(1,1);
cout<<"dot初始的点坐标:\n"<<"x:"<<aDot.getX()<<"\ty:"<<aDot.getY()<<endl;
aDot.move(1,1);
cout<<"dot移动后的的点坐标:\n"<<"x:"<<aDot.getX()<<"\ty:"<<aDot.getY()<<endl;

rectangle rect(2,2);
cout<<"rectangle初始的点坐标:\n"<<"x:"<<rect.getX()<<"\ty:"<<rect.getY()<<endl;
cout<<"ractangle初始的宽和高:\n"<<"w:"<<rect.getW()<<"\th:"<<rect.getH()<<endl;
rect.move(2,2);
cout<<"rectangle变化后的点坐标:\n"<<"x:"<<rect.getX()<<"\ty:"<<rect.getY()<<endl;

cout<<"指针调用:"<<endl;
dot *pt=new triangle(4,4);  //定义基类dot指向派生类对象triangle(4,4)的指针
pt->move(10,10);
pt->showDot();

triangle *pti=new triangle(5,5);    //定义派生类指向自己创建的对象triangle(5,5)的指针
pti->move(10,10);
pti->showDot();

测试截图
在这里插入图片描述

在定义基类时,在函数定义前加上virtual即定义虚函数,虚函数的出现相当于接口,用以实现函数的多态。虚函数里可以放置代码,之后可以进行重写,但是如果不放置代码,而在虚函数后加上=0,这称为纯虚函数,该基类则为抽象类,不能在外部定义抽象类对象。
注意到在定义基类时,不仅将想进行多态的函数进行虚化,还将析构函数也冠以virtual,这是因为如果想delete指向派生类对象的指针时,总是先释放派生类的资源,但是如果基类析构函数并非虚函数,则不会接着释放基类资源,造成内存泄漏。

多继承测试:
inheritance.h

#ifndef INHERITANCE_H
#define INHERITANCE_H
#include<iostream>
#include<stdlib.h>
using namespace std;
class animal{
public :
    void op()
    {
        cout << "hello animal" ;
    };

};

class tiger : public virtual animal {
public :
    void tg()
    {
        cout << "this is  tiger" ;
    };

};

class lion : public virtual animal {
public :
    void lo()
    {
        cout << "this is lion" ;
    };

};

class liger : public tiger, public lion {
public :
    void lo()
    {
        cout << "this is lion" ;
    };

};


#endif // INHERITANCE_H

main.cpp
在这里插入图片描述
当某个类(liger)是多继承的的时候,也许会碰到继承的两个类(lion,tiger)同属于一个基类,这时,基类里的方法( 这里时op() )会在此类中重复,这时用这个类定义的对象调用这个重复的函数时会出现模糊,因为不知道要调用哪一个方法,因为该方法长得一模一样。
这种情况下就需要让那两个类虚继承同一个基类,这样的作用是让这个类(liger)继承的时候,如果有一份父类的拷贝的就用父类的拷贝,如果没有就添加一份,这样就不会有上述所说的模糊结果。

矢量图设计

CShape.h

#pragma once
#ifndef CSHAPE_H
#define CSHAPE_H
#include<string>
#include<math.h>
using namespace std;

class CPoint;
class CRect;
class CTriangle;
class CShape	//定义图形类,定义图形的区域计算、绘画、着色、复制、移动
{
public:
	CShape();
	CShape(const CShape& shape);
	virtual ~CShape();
	virtual double GetArea() const;
	virtual bool ptIn(const CPoint& pt) const;
	virtual bool InRect(const CRect& rc) const;
	virtual void Draw() const;
	virtual void DrawColor();
	virtual CShape* Clone() const;
	virtual CShape& Move(int nOffsetX, int nOffsetY);

protected:
	string m_sName;
};

class CPoint :public CShape {
public:
	int m_nPosX;
	int m_nPosY;
	CPoint() {
		m_nPosX = 0;
		m_nPosY = 0;
	}
	CPoint(int nPosX, int nPosY);
	CPoint(const CPoint& pt);
	virtual ~CPoint();
	double GetArea() const;
	bool ptIn(const CPoint& pt) const;
	bool InRect(const CRect& rc) const;
	void Draw() const;
	void DrawColor();
	CPoint* Clone() const;
	CPoint& Move(int nOffsetX, int nOffsetY);
};
class CTriangle :virtual public CShape {
public:
	CTriangle() {}
	CTriangle(const CPoint& pt1, const CPoint& pt2, const CPoint& pt3);
	CTriangle(const CTriangle& rc);
	CTriangle(const CPoint& pt);
	virtual ~CTriangle();
	double GetArea() const;
	bool ptIn(const CPoint& pt) const;
	bool InRect(const CRect& rc) const;
	void Draw() const;
	void DrawColor();
	CShape* Clone() const;
	CShape& Move(int nOffsetX, int nOffsetY);
	CPoint m_pts[3];
};

class CRect :virtual public CShape {
public:
	CRect() {}
	CRect(CPoint pt1, CPoint pt2);
	CRect(const CRect& rc);
	CRect(CPoint pt1);
	virtual ~CRect();
	double GetArea() const;
	bool ptIn(const CPoint& pt) const;
	bool InRect(const CRect& rc) const;
	void Draw() const;
	void DrawColor();
	CShape* Clone() const;
	CShape& Move(int nOffsetX, int nOffsetY);
	CPoint m_ptLT;
	CPoint m_ptBR;
};

class Comgraphics :public CRect, public CTriangle {
public:
	Comgraphics(const CRect& pt1);
	Comgraphics(const Comgraphics& rc);
	Comgraphics(const CPoint pt1);
	virtual ~Comgraphics();
	double GetArea() const;
	bool ptIn(const CPoint& pt) const;
	bool InRect(const CRect& rc) const;
	void Draw() const;
	void DrawColor();
	CShape* Clone() const;
	CShape& Move(int nOffsetX, int nOffsetY);
	CPoint m_pt1;
	CPoint m_pt2;

};
#endif

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(0x2E, 0x8B, 0x57));
	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(0x00, 0xFF, 0xFF));
	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(EGERGB(0xFF, 0xFF, 0xFF));
	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(EGERGB(0xDC, 0x14, 0x3C));
	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;
}

test1.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(350, 340), CPoint(250, 340), CPoint(300, 440)));
	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;
}

测试截图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

总结

在C++中继承和多态都是为了使程序的延展性提高,而虚继承则提升了抽象对象的上限,使得抽象对象的适配性大幅提高,也能产生新的东西,就像上面的组合图形一般。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值