热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++实验2继承和多态

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档​​​​​文章目录前言一、实验内容二、实验过程2.1继承访问权限测试2.1

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

​​​​​

文章目录

前言

一、实验内容

二、实验过程

2.1 继承访问权限测试

2.1.1 以public方式继承类Person

2.1.2 以protected继承类Person

2.1.2 以private继承类Person

2.2 友元类继承测试

2.2.1 子类为基类友元类时继承权限

2.2.2 友元类对于基类派生类的影响

2.2.3 友元类的派生类对于基类和其派生类的访问权限

2.2.4 友元函数提升某个函数访问权限

2.3 多态性的综合运用

2.3.1 使用virtual修饰函数实现多态性

2.3.2 特殊多态性

2.3.3 析构函数的多态性

 2.3.4 纯虚函数

2.4 构建矢量图

2.4.1 Shapedll.h

2.4.2 Shapedll.cpp

  总结









前言

在此次实验中我将对C++ 类的多继承,虚继承,多态性以及友元函数进行实现练习


提示:以下是本篇文章正文内容,下面案例可供参考





一、实验内容

         一、继承访问权限测试
        1.
设计类A具有public, protected, private等不同属性的成员函数或变量

        2.类B通过public, protected, private等不同方式继承A,在类B的成员函数中测试访问A的成员函数或变量;
        3.在类B中添加public, protected, private等不同属性的成员函数或变量,在外部测试访问B的各个成员函数或变量;

        4.B以private方式继承A,尝试把A中的部分public成员提升为public。
        二、友元类继承测试
        1.设计类A含有私有变量a,在类A中友元给类C;
        2.设计类B继承A,添加私有变量b;在类C中测试访问类B的成员变量a, b;
        3.设计类D继承C,在D的成员函数中测试访问类A的成员变量a,类B的成员变量a, b。
        三、多态性综合运用
        1.一般多态性函数:输入输出参数完全一样,在父类中添加virtual;
        2.特殊多态性函数:输入或输出参数在子类中是父类的指针或基类的引用,在子类中对应的是子类的指针或子类的引用;
        3.析构函数的多态性;(多继承,注意什么情况需要虚继承;)
        4.设计矢量图,运用多继承设计组合图形,要求具备创建不同类型矢量图、选择图形、移动图形、用不同颜色显示图形(表示选中与否),用vector或数组管理图形。
        


二、实验过程





2.1 继承访问权限测试

设计类Person具有public,protected,private三种类型的变量和成员函数,作为父类进行测试不同继承方式下的访问权限

class Person
{
public: //共有函数成员string m_strName;Person();Person(string strName,string strSex,int Age);void SetSex(string strSex){m_strSex = strSex;}protected: //保护数据成员string m_strSex;private: //私有数据成员int m_nAge;
};

类B通过public, protected, private等不同方式继承A,在类B的成员函数中测试访问A的成员函数或变量;

2.1.1 以public方式继承类Person

class Student: public Person
{
public:void SetName(string strName="") //隐含的内联函数{ m_strName = strName; //student通过public继承Person在类的内部可以访问}void SetSex(string strSex="") { m_strSex = strSex;}void SetAge(int Age) { //m_nAge = Age; //public继承方式不能访问private变量}
};
void TestPerson()
{Person perObj;perObj.m_strName = "RenRuijie";//perObj.m_strSex = ""; //父类Person的protected属性在外部无法访问//perObj.m_nAge = 0; //父类private属性在外部也无法访问Student stuObj;stuObj.m_strName = "RenRuijie";//stuObj.m_strSex = "man"; //public继承下,父类的protected属性同样无法在外部被子类访问//stuObj.m_nAge = 0; //public继承下,父类的private属性无法在外部被子类访问
}

2.1.2 以protected继承类Person

使用protected来继承父类,原有权限高于protected的变量都会被降成protected

class Worker:protected Person
{
public:using Person::m_strName;using Person::m_strSex;//using Person::m_nAge; //父类的private属性不能用此方式提升他的访问权限void SetName(string strName="") {m_strName = strName; //Worker通过protected继承Person在类的内部可以访问}void SetSex(string strSex=""){ m_strSex = strSex; //父类protected属性用protected继承也可以访问}void SetAge(int Age){//m_nAge = Age; //protected继承方式不能访问private变量}string & GetName(){return m_strName;}
};
void TestPerson()
{Worker worker;worker.SetName("LiSan");worker.m_strName=""; worker.m_strSex ="man";//worker.m_nAge = 0;//protected继承下,父类的所有变量无法在外部被子类访问,//通过using语句可以提升原访问权限,使其可以在外部被访问//private属性属于私有,用using依旧不可行
}





2.1.2 以private继承类Person

使用private来继承父类,原有权限高于private的变量都会被降成private

//private继承则所有属性变为私有
class Teacher:private Person
{
public:using Person::m_strName; //获得父类成员的方法二using Person::m_strSex;//继承类没有权限访问基类的private属性,只能访问到public和protected属性//using Person::m_nAge;string & GetName() //获得父类成员的方法一{return m_strName;}void SetName(string strName="") {m_strName = strName; //Teacher类通过private继承Person在类的内部可以访问}void SetSex(string strSex=""){ m_strSex = strSex; //父类protected属性用private继承也可以访问}void SetAge(int Age){//m_nAge = Age; //private继承方式不能访问private变量}};
void TestPerson()
{Teacher teacher;//teacher.m_strName = "RenRuijie";//用public,protected,private继承不会影响内部访问,只能访问到protected以上属性,private修饰的成员变量只能在他的类的内部使用//用protected,private继承的不能被外部访问,可以用using提升访问权限到publicteacher.SetSex(""); //SetSex会采取就近调用的方式teacher.GetName();teacher.m_strName = "";teacher.m_strSex = "";//teacher.m_nAge = 10;//若不用using提升访问权限,则父类public,protected,private的变量均无法访问
}

总结:1.类的单继承,class 派生类名: 继承方式 基类名

           2.类的多继承,class 派生类名: 继承方式1   基类名1,继承方式2   基类名2....

           3.继承类只能访问父类protected级以上的变量或成员函数,不能访问private

           4.用public,protected,private继承不会影响内部访问,只能访问到protected以上属性,private

           修饰的成员变量只能在他的类的内部使用

           5.用protected,private继承的不能被外部访问,可以用using提升访问权限到public

           6.改变后该成员在派生类的访问权限由using声明语句之前的派生类访问说明符确定

2.2 友元类继承测试

        将Teacher 类设置为Person类的友元类,对继承权限进行测试

public: //公有函数成员string m_strName; //姓名Person();~Person();Person(string strName,string strSex,int Age);void SetSex(string strSex){m_strSex &#61; strSex;}friend class Teacher; //将Teacher类设置成Person类的友元类&#xff0c;使其子类所有函数均可访问父类成员friend istream & operator>>(istream &is,Person &per);friend ostream & operator<<(ostream &os,const Person &person);bool Create(string strName,string strSex,int Age);protected: //保护数据成员string m_strSex; //性别private: //私有数据成员int m_nAge; //年龄
};

2.2.1 子类为基类友元类时继承权限

class Teacher:private Person
{
public://using Person::m_strName;//using Person::m_strSex;//using Person::m_nAge;string &GetName(){return m_strName;}void SetSex(string strSex&#61;""){m_strName&#61;"";m_strSex&#61;strSex;m_nAge&#61;10; //通过设置友元类&#xff0c;子类可访问父类的私有变量}//int GetAge(){m_nAge&#61;20;}protected:
private:
};
void TestTeacher()
{//测试友元类对继承的影响Teacher tea;//tea.m_strName &#61;"SYP";//tea.m_strSex &#61;"man"; //设置为友元类时用private继承&#xff0c;同样不能访问父类成员
}

将Teacher类作为Person类的友元类时&#xff0c;用private继承在子类内部可以访问父类所有成员&#xff0c;包括private变量&#xff0c;但是在外部都不能进行访问。

2.2.2 友元类对于基类派生类的影响

class Teacher:private Person
{
public://using Person::m_strName;//using Person::m_strSex;//using Person::m_nAge;Teacher();~Teacher();string &GetName(){return m_strName;}void SetSex(string strSex&#61;""){m_strName&#61;"";m_strSex&#61;strSex;m_nAge&#61;10; //通过设置友元类&#xff0c;子类可访问父类的私有变量}void TestTeacher(){m_nAge &#61;100; //Teacher设置为Person的友元类&#xff0c;可以访问基类Person的私有变量m_nScore &#61; 100; //无法执行&#xff0c;无法访问基类Person的其余派生类Student的私有变量}int GetAge(){m_nAge&#61;20;}protected:
private:
};
class Student: public Person
{
public:Student();~Student();void SetName(string strName&#61;"") //隐含的内联函数{m_strName &#61; strName; //student通过public继承Person在类的内部可以访问}void SetSex(string strSex&#61;""){ m_strSex &#61; strSex;}void SetAge(int Age){//m_nAge &#61; Age; //public继承方式不能访问private变量}inline string GetSex();
protected:double m_nNumber; //学生成绩
private:string m_nScore; //学生学号
};

通过测试发现&#xff0c;基类的友元类在他的内部可以访问基类的私有变量&#xff0c;但是却不能对基类其他派生类产生此种影响。

2.2.3 友元类的派生类对于基类和其派生类的访问权限

class Lecturer:public Teacher
{
public:Lecturer();~Lecturer();void TestLecturer(){Student stu;m_nAge &#61; 0; //基类的私有变量无法访问stu.m_nAge &#61; 0;stu.m_nScore &#61; 0; //基类派生类的私有变量也无法访问 }
protected:
private:
};

2.2.4 友元函数提升某个函数访问权限

class A;
class Person;
class A
{
public:void TestFriend(Person &per);void TestFriend2(Person &per){//per.m_nAge &#61; 10;}
};
class Person
{
public: //公有函数成员string m_strName; //姓名Person();~Person();Person(string strName,string strSex,int Age);void SetSex(string strSex){m_strSex &#61; strSex;}friend class Teacher; //将Teacher类设置成Person类的友元类&#xff0c;使其子类所有函数均可访问父类成员friend void A::TestFriend(Person &per); //友元成员函数,只允许TestFriend()访问私有变量//友元成员函数&#xff1a;在类A的内部声明一个属于类B的成员函数&#xff0c;则只有该成员才能访问类A的私有成员friend void TestFriendFun(Person &per) //友元函数&#xff08;全局&#xff09;,同样可以访问私有变量&#xff08;第一种实现方式&#xff1a;实现过程在类的内部&#xff09;{per.m_nAge &#61;20;}friend void TestFriendFun(Person &per); //第二种实现方式&#xff1a;实现过程在类的外部friend istream & operator>>(istream &is,Person &per);friend ostream & operator<<(ostream &os,const Person &person);bool Create(string strName,string strSex,int Age);protected: //保护数据成员string m_strSex; //性别private: //私有数据成员int m_nAge; //年龄
};
/*
void TestFriendFun(Person &per) //友元函数&#xff08;全局&#xff09;,同样可以访问私有变量
{per.m_nAge &#61;20;
}
*/
void A::TestFriend(Person &per)
{per.m_nAge &#61; 0;
}

注&#xff1a;

1.友元函数是在类中用关键字friend修饰的非成员函数。友元函数可以是一个普通的函数&#xff0c;也可以是其他类的成员函数&#xff0c;虽然他不是本类的成员函数&#xff0c;但是在他的函数体中可以通过对象名访问类的私有和保护成员。友元函数是其他类的成员函数&#xff0c;如在类A 的内部声明一个属于类B的成员函数&#xff0c;则该成员函数可以访问类A的私有和保护变量&#xff08;例&#xff1a;friend void A::TestFriend(Person &per);&#xff09;。

2.若类A 为类B 的友元类&#xff0c;则A类的所有成员函数都是类B 的友元函数&#xff0c;都可以访问类B的私有和保护成员。

3.友元关系是不具有传递性&#xff0c;类B是类A 的友元&#xff0c;类C是类B 的友元&#xff0c;类C和类A之间如果没有声明&#xff0c;就没有任何友元关系&#xff0c;不能进行数据共享。

4.友元关系是单向的&#xff0c;不具有交换性&#xff0c;如果声明类B是类A的友元&#xff0c;类B的成员函数就可以访问类A的私有和保护数据&#xff0c;但类A的成员函数却不能访问类B的私有、保护数据。

5.友元关系是不被继承的&#xff0c;如果类B是类A的友元&#xff0c;类B的派生类并不会自动称为类A的友元。

2.3 多态性的综合运用


2.3.1 使用virtual修饰函数实现多态性

如果用基类类型的指针指向派生类对象&#xff0c;就可以通过这个指针来访问该对象&#xff0c;问题是访问到的只是从基类继承来的同名成员。解决这一问题的办法是&#xff1a;如果需要通过基类的指针指向派生类的对象&#xff0c;并访问某个与基类同名的成员&#xff0c;那么首先在基类中将这个同名函数说明为虚函数。这样通过基类类型的指针&#xff0c;就可以使属于不同派生类的不同对象产生不同的行为&#xff0c;从而实现了运行过程的多态。

class Person //A类
{
public: //公有函数成员string m_strName; //姓名Person();virtual ~Person();Person(string strName,string strSex,int Age);virtual void SetType();void SetSex(string strSex){m_strSex &#61; strSex;}friend istream & operator>>(istream &is,Person &per);friend ostream & operator<<(ostream &os,const Person &person);bool Create(string strName,string strSex,int Age);protected: //保护数据成员string m_strSex; //性别private: //私有数据成员int m_nAge; //年龄
};//类的单继承&#xff0c;class 派生类名: 继承方式 基类名
//继承类只能访问父类protected级以上的变量或成员函数&#xff0c;不能访问private
class Student: public Person //B类
{
public:Student();~Student();void SetType();void SetName(string strName&#61;"") //隐含的内联函数{m_strName &#61; strName; //student通过public继承Person在类的内部可以访问}void SetSex(string strSex&#61;""){ m_strSex &#61; strSex;}void SetAge(int Age){//m_nAge &#61; Age; //public继承方式不能访问private变量}inline string GetSex();
protected:double m_nNumber; //学生成绩
private:string m_nScore; //学生学号
};
int main(int argc, char *argv[])
{Person *stu &#61; new Student(); //基类使用派生类的构造器&#xff0c;基类类型的指针指向派生类对象stu->SetType(); //使用基类和派生类都实现的setType()函数测试真正调用的是哪一个return 0;
}

输出结果为“My class is student!” &#xff0c;表明调用的是Student类中的setType()函数。说明当使用虚函数继承机制的时候&#xff0c;会调用派生类中的函数&#xff0c;而不是基类。

2.3.2 特殊多态性

输入或输出参数在子类中是父类的指针或基类的引用&#xff0c;在子类中对应的是子类的指针或子类的引用&#xff1b;假如传入的是派生类&#xff0c;同样希望函数保留派生类的多态&#xff0c;即根据传入参数类型调用相应函数。

定义一个全局函数SetType,在声明中我们定义传入参数类型为Person,对传入不同的参数进行测试。

void TestType(Person *p) //传入的是基类的指针
{p->SetType();
}
int main(int argc, char *argv[])
{Person *stu &#61; new Student(); //基类使用派生类的构造器&#xff0c;基类类型的指针指向派生类对象stu->SetType(); //使用基类和派生类都实现的setType()函数测试真正调用的是哪一个Person p1;Student s1;TestType(&p1);TestType(&s1);return 0;
}

或 

void TestType(Person &p) //传入的是基类的引用
{p.SetType();
}int main(int argc, char *argv[])
{Person *stu &#61; new Student(); //基类使用派生类的构造器&#xff0c;基类类型的指针指向派生类对象stu->SetType(); //使用基类和派生类都实现的setType()函数测试真正调用的是哪一个Person p1;Student s1;TestType(p1);TestType(s1);return 0;
}

运行结果均为&#xff1a;

这样通过传入参数的不同调用相应的方法&#xff0c;实现了参数传值的多态性。


2.3.3 析构函数的多态性

假如我们用基类的指针创建一个子类的对象&#xff0c;那么在delete的时候执行的就是基类的析构函数&#xff0c;子类虽然继承了基类&#xff0c;但是却没有重写基类的析构函数&#xff0c;则无法析构子类的指针&#xff0c;可能会造成内存泄漏。

Person::~Person()
{cout<<"delete Person!"<}Student::~Student()
{cout<<"delete Student!"<}
int main(int argc, char *argv[])
{Person *stu &#61; new Student(); //基类使用派生类的构造器&#xff0c;基类类型的指针指向派生类对象stu->SetType(); //使用基类和派生类都实现的setType()函数测试真正调用的是哪一个delete stu;return 0;
}

运行结果&#xff1a;

 可以看出只执行了基类的析构函数&#xff0c;解决方法是将基类的析构函数用virtual修饰&#xff0c;设置为虚函数就可以实现析构函数的多态性。

class Person //A类
{
public: //公有函数成员string m_strName; //姓名Person();virtual ~Person();Person(string strName,string strSex,int Age);virtual void SetType();friend istream & operator>>(istream &is,Person &per);friend ostream & operator<<(ostream &os,const Person &person);bool Create(string strName,string strSex,int Age);protected: //保护数据成员string m_strSex; //性别private: //私有数据成员int m_nAge; //年龄
};

运行结果&#xff1a;

用virtual修饰后&#xff0c;delete子类时就会先执行子类的析构函数&#xff0c;再执行父类的析构函数。

 2.3.4 纯虚函数

在一个类中&#xff0c;若在其成员函数后面加上 &#61;0&#xff0c;则该函数为纯虚函数&#xff0c;如下&#xff1a;

class Person //A类
{
public: //公有函数成员string m_strName; //姓名Person();virtual ~Person();Person(string strName,string strSex,int Age);virtual void SetType();virtual void SetWork() &#61;0; //纯虚函数void SetSex(string strSex){m_strSex &#61; strSex;}
}

纯虚函数的特点&#xff1a;

1.纯虚函数只有函数声明&#xff0c;没有函数体&#xff0c;不具备函数的功能&#xff0c;不能被调用&#xff1b;

2.纯虚函数的作用是在基类中为其派生类保留一个函数的名字&#xff0c;以便派生类根据所需对其进行定义。

3.含有纯虚函数的类称为抽象类&#xff08;虚基类&#xff09;&#xff0c;它不能生成对象。同时基类中对纯虚函数没有定义&#xff0c;在派生类中必须加以实现。

4.与纯虚函数函数不同的是虚函数为了重载和多态的需要&#xff0c;在基类中是有定义的&#xff0c;即便定义为空&#xff0c;所以子类中可以重写也可以不重写基类的函数&#xff0c;而纯虚函数在子类中必须加以实现。

2.4 构建矢量图

运用多继承设计组合图形&#xff0c;要求具备创建不同类型矢量图、选择图形、移动图形、用不同颜色显示图形&#xff08;表示选中与否&#xff09;&#xff0c;用vector或数组管理图形&#xff0c;实现了shapeDll类,CShape类&#xff0c;CPoint类&#xff0c;CRect类&#xff0c;CRectPoint类&#xff0c;以及图形管理类ShapeManager类

2.4.1 Shapedll.h

#include
#include
#include
#include
//容器头文件&#xff0c;相比数组的优点是在于能根据需要随时自动调整自身大小以便容下所有元素using namespace std;class SHAPEDLL_EXPORT ShapeDll
{
public:ShapeDll();
};
class CPoint;
class CRect;
class SHAPEDLL_EXPORT CShape
{
public:CShape();//CShape(string strName):m_sName(){};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(QPainter & painter) const;virtual CShape* Clone() const;virtual CShape& Move(int nOffsetX,int nOffsetY);
protected:string m_sName;
};
class SHAPEDLL_EXPORT CPoint:public CShape
{public:int m_nPosX;int m_nPosY;CPoint(); //如果基类没有默认构造函数&#xff0c;则派生类也会无此方法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; //呈现多态的方式一&#xff1a;指针CPoint& Move(int nOffsetX,int nOffsetY); //呈现多态的方式二&#xff1a;引用
};
//绘制矩形类
class SHAPEDLL_EXPORT CRect:public CShape
{
public:CPoint m_ptLT;CPoint m_ptBR;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);};
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);};
//图形管理类
class ShapesManager
{
public:
private:vector m_pShapes;ShapesManager();~ShapesManager();void AddShape(CShape* pShape); //添加一个图形void DelShape(CShape* pShape); //删除一个图形void AddShapes(vector pShape);void DelShapes(vector pShape);void DelAll(); //删除所有图形};#endif // SHAPEDLL_H

2.4.2 Shapedll.cpp

#include "shapedll.h"
#include
using namespace std;
ShapeDll::ShapeDll()
{
}
CShape::CShape()
{}
CShape::CShape(const CShape & shape)
{m_sName &#61; shape.m_sName;
}
CShape::~CShape()
{cout<<"CShape::~CShape()\n";
}
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(QPainter & painter) const
{}
CShape* CShape::Clone() const
{return new CShape(*this);
}
CShape& CShape::Move(int nOffsetX,int nOffsetY)
{return *this;
}
//Cpoint成员函数实现
CPoint::CPoint()
{}
CPoint::~CPoint()
{cout<<"CPoint::~CPoint()\n";
}
CPoint::CPoint(int nPosX,int nPosY)
{m_nPosX &#61; nPosX;m_nPosY &#61; nPosY;
}
CPoint::CPoint(const CPoint & pt)
{m_nPosX &#61; pt.m_nPosX;m_nPosY &#61; pt.m_nPosY;
}double CPoint::GetArea() const
{return 0;
}
//判断某个点是否在图形范围内
bool CPoint::ptIn(const CPoint& pt) const
{return (pt.m_nPosX-m_nPosX)*(pt.m_nPosX-m_nPosX)&#43;(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_nPosXrc.m_ptLT.m_nPosY && m_nPosY}
void CPoint::Draw(QPainter & painter) const
{painter.drawPoint(m_nPosX,m_nPosY); //绘制点&#xff0c;通过指定端点坐标绘制&#xff0c;只能绘制单个点&#xff08;点的X坐标&#xff0c;Y坐标&#xff09;//若要绘制多个点则使用drawPoints()方法
}
CPoint* CPoint::Clone() const //拷贝构造函数
{return new CPoint(m_nPosX,m_nPosY);//等同于//return new CPoint(*this);
}
CPoint& CPoint::Move(int nOffsetX,int nOffsetY)
{m_nPosX &#43;&#61;nOffsetX;m_nPosX &#43;&#61;nOffsetY;return *this;
}//CRect成员函数实现
CRect::CRect(CPoint pt1,CPoint pt2) //矩形的左上和右下角
{m_ptLT &#61;pt1;m_ptBR &#61;pt2;
}
CRect::CRect(const CRect & rc)
{m_ptLT &#61; rc.m_ptLT;m_ptBR &#61; rc.m_ptBR;
}
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 //判断点是否在矩形内
{ //第一个const表示在此函数内不能修改pt,第二个const表示在该方法下不能修改CRect类中任何成员return (pt.m_nPosX>m_ptLT.m_nPosX &&pt.m_nPosXm_ptLT.m_nPosY &&pt.m_nPosY}
bool CRect::InRect(const CRect& rc) const
{return rc.ptIn(m_ptLT) && rc.ptIn(m_ptBR);
}
void CRect::Draw(QPainter & painter) const
{//绘制矩形painter.drawRect(m_ptLT.m_nPosX,m_ptBR.m_nPosY, //左上点&#xff0c;右下点m_ptBR.m_nPosX - m_ptLT.m_nPosX, //矩形的宽m_ptBR.m_nPosY-m_ptLT.m_nPosY); //矩形的高
}
CRect* CRect::Clone() const
{return new CRect(*this);
}
//void CRect::Move(int nOffsetX,int nOffsetY); //没有返回值则则只能move一次
CRect& CRect::Move(int nOffsetX,int nOffsetY) //有返回值可连续move
{m_ptLT.m_nPosX &#43;&#61; nOffsetX;m_ptLT.m_nPosY &#43;&#61; nOffsetY;m_ptBR.m_nPosX &#43;&#61; nOffsetX;m_ptBR.m_nPosY &#43;&#61; nOffsetY;return *this;
}//CRectPoint成员函数实现
CRectPoint::CRectPoint(CPoint pt1,CPoint pt2):CRect(pt1,pt2),CPoint((pt1.m_nPosX&#43;pt1.m_nPosX)/2,(pt1.m_nPosY&#43;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);return *this;
}
//ShapesManager的成员函数
void ShapesManager::AddShape(CShape * pShape)
{m_pShapes.push_back(pShape);
}
void ShapesManager::DelShape(CShape * pShape)
{for(vector::iterator it&#61;m_pShapes.begin();it!&#61;m_pShapes.end();it&#43;&#43;){if((*it) !&#61; pShape){delete pShape;m_pShapes.erase(it);break;}}
}
void ShapesManager::AddShapes(vector pShape)
{m_pShapes.insert(m_pShapes.begin(),pShape.begin(),pShape.end());
}
void ShapesManager::DelShapes(vector pShape)
{for (vector::iterator it &#61; m_pShapes.begin();it!&#61;m_pShapes.end();it&#43;&#43;){DelShape(*it);}
}
void ShapesManager::DelAll()
{for (vector::iterator it &#61; m_pShapes.begin();it!&#61;m_pShapes.end();it&#43;&#43;){delete *it;}m_pShapes.clear();
}void Test()
{CShape *pShape &#61; new CPoint();delete pShape;pShape &#61; new CRect(CPoint(0,0),CPoint(100,100));pShape->Move(10,10).Move(20,20).Move(40,40);
}



总结

1.继承权限

用protected,private继承的不能被外部访问&#xff0c;可以用using提升访问权限到public&#xff0c;改变后该成员在派生类的访问权限由using声明语句之前的派生类访问说明符确定。

2.多态性&#xff1a;是指具有不同功能的函数可以用一个函数名&#xff0c;这样就可以用一个函数名调用不同内容的函数。在C&#43;&#43;中分为静态多态和动态多态两种&#xff0c;在程序运行前就完成联编的称为静态多态&#xff0c;主要通过函数重载和模板实现&#xff0c;动态多态在程序运行时才完成联编&#xff0c;主要通过虚函数实现。

函数重载:

void print_hello(string name){
cout << "hello " << name << endl;;
}void print_hello(string name1, string name2){
cout << "hello, " <}

虚函数&#xff1a;

class A
{
public:virtual void fun(){cout << “hello A” << endl;}
};
class B:public A
{public:virtual void fun(){cout << “hello B” << endl;}
}
int main()
{A a &#61; new A();a->fun();a &#61; new B();a->fun();return 0;
}
out&#xff1a;
hello A
hello B

对于一个继承体系来说&#xff0c;如果在基类的函数前加上virtual关键字&#xff0c;在派生类中重写该函数&#xff0c;运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类&#xff0c;就调用派生类的函数&#xff1b;如果对象类型是基类&#xff0c;就调用基类的函数。

虚函数&#xff1a;用virtual声明的函数

虚函数的声明:  virtual 函数类型 函数名&#xff08;形参表&#xff09;;
虚函数声明只能出现在类定义中的函数原型声明中&#xff0c;而不能在成员函数实现的时候。
在派生类中可以对基类中的成员函数进行覆盖。
虚函数一般不声明为内联函数&#xff0c;因为对虚函数的调用需要动态绑定&#xff0c;而对内联函数的处理是静态的。

派生类可以不显式地用virtual声明虚函数&#xff0c;这时系统就会用以下规则来判断派生类的一个函数成员是不是虚函数&#xff1a;
(1)该函数是否与基类的虚函数有相同的名称、参数个数及对应参数类型&#xff1b;
(2)该函数是否与基类的虚函数有相同的返回值或者满足类型兼容规则的指针、引用型的返回值&#xff1b;
如果从名称、参数及返回值三个方面检查之后&#xff0c;派生类的函数满足上述条件&#xff0c;就会自动确定为虚函数。这时&#xff0c;派生类的虚函数便覆盖了基类的虚函数。一般也会将派生类中的函数用virtual修饰&#xff0c;方便识别其为虚函数。

通过这次实验我学习了C&#43;&#43;中类的三种继承方式权限的区别&#xff0c;以及用using语句提升部分权限&#xff0c;还测试使用了友元函数&#xff0c;多态性。但是没有掌握矢量图的设置&#xff0c;以及如何可视化来进行测试绘制矢量图的相关函数。


推荐阅读
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
author-avatar
asd54w464wq_212
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有