C++第二次实验:继承和多态
继承访问权限测试
- 设计类A具有public, protected, private等不同属性的成员函数或变量
class base {
public:
int q=10;//外部只能访问到这一步
protected:
int w = 11;//子类只能访问到基类的这一步
private:
int e = 12;//无法被外部访问
};
-
实现类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关键字的函数就是虚拟函数.
虚函数是指一个类中你希望重载的成员函数 ,当你用一个基类指针或引用指向一个继承类对象的时候,调用一个虚函数时, 实际调用的是继承类的版本,它可以在运行时判断指针指向的对象,并自动调用相应的函数.
虚函数最关键的特点是“动态联编”,它可以在运行时判断指针指向的对象,并自动调用相应的函数。