C++(二):继承和多态

继承访问权限测试

  1. 设计类A具有public, protected, private等不同属性的成员函数或变量
class base {
public:
	int q=10;//外部只能访问到这一步
protected:
	int w = 11;//子类只能访问到基类的这一步
private:
	int e = 12;//无法被外部访问
};
  1. 实现类B通过public, protected, private等不同方式继承A,在类B的成员函数中测试访问A的成员函数或变量;

    1、使用public继承类base
    子函数使用public继承类A时,在子函数内部只能访问到protected部分,外部访问只能访问到public部分

class Pub_b :public base {
public:
	void Test() {
		q = 10;
		w = 10;
		//e = 10;//无法访问
	}

	int Pub_pub_b1 = 10;
protected:
	int Pub_pro_b2 = 11;
private:
	int Pub_pri_b3 = 12;
};

此时的输出:
在这里插入图片描述
既只能访问到public部分

2、使用protected继承类base

class Pro_B :protected base {
public:
	void Test() {
		q = 10;
		w = 10;
		//c = 10;//无法访问
	}

	int Pro_pub_b1 = 1;
protected:
	int Pro_pro_b2 = 2;
private:
	int Pro_pri_b3 = 3;
};

此时的输出结果:
在这里插入图片描述
既以protected方式继承的外部不能访问继承到的public部分成员,只能访问到自己定义的public成员

3、使用private继承类base

class Pri_B :private base {
public:
	void Test() {
		q = 10;
		w = 10;
		//c = 10;//无法访问
	}

	int Pri_pub_b1 = 4;
protected:
	int Pri_pro_b2 = 5;
private:
	int Pri_pri_b3 = 6;
};

此时的输出:
在这里插入图片描述

4、以private方式继承A,尝试把base中的部分public成员提升为public。
using的作用:在子类中引用基类的成员
newPri_B私有继承base类,所以base类中公有成员q不能被外部访问,但使用using后可以在main中访问到q

class newPri_B :private base {
public:
	void Test() {
		q = 100;
		w = 100;
		//c = 10;//无法访问
	}
	int pri_pub_b1 = 7;
	using base::q;
protected:
	int Pri_pro_b2 = 8;
private:
	int Pri_pri_b3 = 9;
};

输出:
在这里插入图片描述

友元类继承

1、设计类A含有私有变量a,在类A中友元给类C

class A {
public:
	int a = 10;
protected:
	int b = 1;
private:
	int c = 2;
	friend class C;//友元,使c可以访问到A的私有变量c的值
};

2、设计类B继承A,添加私有变量b;在类C中测试访问类B的成员变量a, b;

class B :public A {
private:
	int b=3;
};

class C {
public:
	void Test() {
		B b1;
		b1.a;
		//b1.b; 不可访问
		A a1;
		a1.c;//因为上面通过友元函数使得c的成员可以访问到A的私有变量
		
	}
	int a;
};

3、设计类D继承C,在D的成员函数中测试访问类A的成员变量a,类B的成员变量a, b。

class D :public C {
public:
	void Test() {
		A a1;
		a1.a;
		//a1.c; 不可访问
		//友元函数:朋友可以访问,朋友的儿子不能访问
		B b2;
		b2.a;
		//b2.b;
	}
};

多态的综合性运用

一般多态性函数:输入输出参数完全一样,在父类中添加virtual

class A {

public:
	int a = 1;
	virtual void func1();
	void func2();
protected:
	int b = 2;
private:
	int c = 3;

}Base;

特殊多态性函数:输入或输出参数在子类中是父类的指针或基类的引用,在子类中对于的是子类的指针或子类的引用

class A {

public:
	int a = 1;
	virtual void func1();
	void func2();
protected:
	int b = 2;
private:
	int c = 3;

}Base;
void A :: func1() {
	cout << "这是基类,这是func1" << endl;
}

void A::func2() {
	cout << "这是基类,这是func2" << endl;
}

class B : public A {
	void func1();
	void func2();
}Son;

void B::func1() {
	cout << "这是子类,这是func1" << endl;
}

void B::func2() {
	cout << "这是子类,这是func2" << endl;
}
int main(int argc, char* argv[]) {
	A* a;
	if (_getch() == 'c') {
		a = &Son;
	}
	else a = &Base;
	a->func1();
	a->func2();
}

此时的输出结果:
当输入为c时
在这里插入图片描述
当输入不为c时
在这里插入图片描述

析构函数的多态性

虚析构函数可以防止内存泄漏

class A {

public:
	int a = 1;
	virtual void func1();
	void func2();
	virtual ~A();
protected:
	int b = 2;
private:
	int c = 3;

}Base;

多继承

使用虚继承的要求:当出现多重继承并且继承关系是一个环时使用虚继承

class A {

public:
	int a = 1;
	virtual void func1();
	void func2();
protected:
	int b = 2;
private:
	int c = 3;

}Base;
class B1 :public virtual A {
public:
	void Test() {
		a = 11;
		b = 12;
	}
	int b = 101;
};

class B2 :public virtual A {
public:
	void Test() {
		a = 11;
		b = 12;
	}
	int b = 1111;
};
class D :public B1, public B2 {
public:
	void Test() {
		B1_b = 12;
		B2_b = 15;
	}
	int d = 10;
};

设计矢量图,运用多继承设计组合图形,要求具备创建不同类型矢量图、选择图形、移动图形、用不同颜色显示图形(表示选中与否),用vector或数组管理图形。

shapeDll.h

#ifndef SHAPEDLL_H
#define SHAPEDLL_H
#include <string>
#include <math.h>
#include <QPainter>
#include <vector>
using namespace std;

#include "ShapeDll_global.h"

class SHAPEDLL_EXPORT ShapeDll
{
public:
    ShapeDll();
};


class CPoint;
class CRect;
class SHAPEDLL_EXPORT CShape{
public:
    //如果没有这个默认构造函数,后续继承的一些遍历的构造函数会出现问题
    //原因:后续的继承的构造的前提是基类要先构造出来
    //如果不使用构造的话要在后续指出怎么构造的
    CShape();
    CShape(const CShape & shape);
    virtual ~CShape();
    //纯虚函数,既该函数不需要实现
    //virtual double GetArea() const=0;
    virtual double GetArea() const;
    virtual bool ptIn(const CPoint& pt)const;
    virtual bool InRect(const CPoint& rc)const;
    virtual void Draw(QPainter & painter)const;
    virtual CShape* Clone() const;
    virtual CShape&Move(int nOffsetX,int nOffsetY);
protected:
    string m_sName;
};

//不同返回类型依然能够呈现多态的原因
//CPoint是CShape的继承类,所以CShape* 和CPoint* 能够呈现多态
//但是CShape和Cpoint不能呈现多态

class SHAPEDLL_EXPORT CPoint:virtual public CShape{
public:
    int m_nPosX;
    int m_nPosY;
    CPoint(){};
    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(QPainter & painter) const;
    CPoint* CLone() const;
    CPoint& Move(int nOffsetX,int nOffsetY);
    //使用引用方式呈现多态
};

class SHAPEDLL_EXPORT CTriangle:virtual public CShape{
public:
    CTriangle(const CPoint& pt1,const CPoint& pt2,const CPoint& pt3);
    CTriangle(const CTriangle &rc);
    virtual ~CTriangle();
    double GetArea() const;
    bool ptIn(const CPoint & pt) const;
    bool InRect(const CRect & rc) const;
    void Draw(QPainter & painter) const;
    CTriangle* Clone() const;
    CTriangle& Move(int nOffsetX,int nOffsetY);
    CPoint m_pts[3];
};


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

class SHAPEDLL_EXPORT CCircle:virtual public CShape{
public:
    CCircle(CPoint ptCenter,double dR);
    CCircle(const CCircle & rc);
    virtual ~CCircle();
    double GetArea() const;
    bool ptIn(const CPoint&pt) const;
    bool InRect(const CRect& rc)const;
    void Draw(QPainter &painter)const;
    CCircle* Clone() const;
    CCircle& Move(int nOffsetX,int nOffsetY);

    CPoint m_ptCenter;
    double m_dR;
};

class SHAPEDLL_EXPORT CircleInRect:public CCircle,public CRect{
public:
    CircleInRect(CPoint ptCenter,double dR);
    CircleInRect(const CircleInRect& rc);
    virtual ~CircleInRect();
    double GetArea() const;
    bool ptIn(const CPoint& pt) const;
    bool InRect(const CRect& rc) const;
    void Draw(QPainter & painter) const;
    CircleInRect* Clone() const;
    CircleInRect& Move(int nOffsetX,int nOffsetY);
};

class ShapesManger{
public:
    ShapesManger(){};
    void AddShape(CShape* pShape);
    void Remove(CShape* pShape);
    void Add(vector<CShape*> pshapes);
    void Remove(vector<CShape*> pshapes);
    void RemoveAll();
    ~ShapesManger();//需要释放内存

    CShape * ptIn(const CPoint& pt);
    bool InRect(const CRect& rc,vector<CShape*> &shapesOut);
    void Draw(QPainter& painter,vector<CShape*> &shapes);
    void Draw(QPainter& painter);
    void Clone(vector<CShape*>& shapesIn,vector<CShape*>& shapesOut);
    void Move(int nOffsetX,int nOffsetY,vector<CShape*>&shapes);
private:
    //m_pShapes存储CShape的指针
    vector<CShape*> m_pShapes;
};


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

#endif // SHAPEDLL_H

shapedll.cpp

#include "shapedll.h"

ShapeDll::ShapeDll()
{
}

CShape::CShape(){

}
CShape::CShape(const CShape & shape){

}
CShape::~CShape(){

}
double CShape::GetArea() const{

}
bool CShape::ptIn(const CPoint& pt)const{
    return false;
}
bool CShape::InRect(const CPoint& rc)const{
    return false;
}
void CShape::Draw(QPainter & painter)const{

}
CShape* CShape::Clone() const{

}
CShape& CShape::Move(int nOffsetX,int nOffsetY){

}

CPoint::CPoint(int nPosX,int nPosY){
    m_nPosX = nPosX;
    m_nPosY = nPosY;
}
CPoint::CPoint(const CPoint &pt){

}

CPoint::~CPoint(){

}
double CPoint::GetArea() const{
    return 0;
}
bool CPoint::ptIn(const CPoint& pt) const{
    return (pt.m_nPosX-m_nPosX)*(pt.m_nPosX-m_nPosX) +
            (pt.m_nPosY-m_nPosY)*(pt.m_nPosY-m_nPosY)<4;
}
bool CPoint::InRect(const CRect& rc) const{
    return(m_nPosX>rc.m_ptLT.m_nPosX && m_nPosX<rc.m_ptBR.m_nPosX,
    m_nPosY>rc.m_ptLT.m_nPosY && m_nPosY<rc.m_ptBR.m_nPosY);
}
void CPoint::Draw(QPainter & painter) const{
    painter.drawPoint(m_nPosX,m_nPosY);
}

//返回一个新的对象
CPoint* CPoint::CLone() const{
    return new CPoint(m_nPosX,m_nPosY);
    //二者等价
    //return new CPoint(*this);
}
CPoint& CPoint::Move(int nOffsetX,int nOffsetY){
    m_nPosX += nOffsetX;
    m_nPosY += nOffsetY;
    return *this;
}

//矩形的左上和右下角两个点
CRect::CRect(CPoint pt1,CPoint pt2){
    m_ptLT = pt1;
    m_ptBR = pt2;
}
CRect::CRect(const CRect&rc){
    m_ptLT = rc.m_ptLT;
    m_ptBR = rc.m_ptBR;
}
CRect::~CRect(){

}
double CRect::GetArea() const{
    return 0;
}
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 false;
}

//drawPolygon:封闭的线,整个面都会刷掉
//draePolyline:不封闭的线,单纯画线
void CRect::Draw(QPainter & painter) const{
    painter.drawRect(m_ptLT.m_nPosX,m_ptBR.m_nPosY,
                     m_ptBR.m_nPosX-m_ptLT.m_nPosX,
                     m_ptBR.m_nPosY-m_ptLT.m_nPosY);
}
CRect* CRect::Clone() const{
    new CRect(*this);
}

//有返回值可以连续move
CRect& CRect::Move(int nOffsetX,int nOffsetY){

    m_ptLT.m_nPosX += nOffsetX;
    m_ptLT.m_nPosY += nOffsetY;

    m_ptBR.m_nPosX += nOffsetX;
    m_ptBR.m_nPosY += nOffsetY;
    return *this;
}

CRectPoint::CRectPoint(CPoint pt1,CPoint pt2):
    CRect(pt1,pt2),
    CPoint((pt1.m_nPosX+pt1.m_nPosX)/2,(pt1.m_nPosY+pt1.m_nPosY)/2)
{

}

CRectPoint::CRectPoint(const CRectPoint&rc):
        CRect(rc.m_ptLT,rc.m_ptBR),
        CPoint(rc.m_nPosX,rc.m_nPosY)
{

}

CRectPoint::~CRectPoint(){

}

double CRectPoint::GetArea() const{
    return 0;
}

bool CRectPoint::ptIn(const CPoint& pt) const{
    return CRect::ptIn(pt);
}
bool CRectPoint::InRect(const CRect& rc) const{
    return CRect::InRect(rc);
}
void CRectPoint::Draw(QPainter & painter) const{

    CRect::Draw(painter);
    CPoint::Draw(painter);
}
CRectPoint* CRectPoint::Clone() const{
    return new CRectPoint(*this);
}
CRectPoint& CRectPoint::Move(int nOffsetX,int nOffsetY){
    CRect::Move(nOffsetX,nOffsetY);
    CPoint::Move(nOffsetX,nOffsetY);
}

void ShapesManger::AddShape(CShape* pShape){
    m_pShapes.push_back(pShape);
}

void ShapesManger::Remove(CShape* pShape){
    //end
    for(vector<CShape*>::iterator it=m_pShapes.begin();
        it!=m_pShapes.end();it++)
    {
        if((*it) != pShape){
            delete  pShape;
            m_pShapes.erase(it);
            break;
        }
    }
}


void Add(vector<CShape*> pshapes){

}

void Test(){
    //如果没加virtual,那么调用的是CShape的delete
    //而不是CPoint的delete
    CShape * pShape = new CPoint();
    delete pShape;

    pShape = new CRect(CPoint(0,0),CPoint(100,100));
    pShape->Move(10,10).Move(10,10);

}

出现的错误

1、内存越界
在这里插入图片描述
将类class A改为class base解决错误,应该是在另外一个cpp文件中也定义了A导致出错。

2、存在多个cpp文件时,会存在多个main函数,使得运行时会报错
解决:可以将没用到的cpp文件的main函数注释掉

总结

virtual:在类中加了Virtual关键字的函数就是虚拟函数.
虚函数是指一个类中你希望重载的成员函数 ,当你用一个基类指针或引用指向一个继承类对象的时候,调用一个虚函数时, 实际调用的是继承类的版本,它可以在运行时判断指针指向的对象,并自动调用相应的函数.
虚函数最关键的特点是“动态联编”,它可以在运行时判断指针指向的对象,并自动调用相应的函数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值