C++程序设计
实验报告
一、实验目的
本次实验所涉及并要求掌握的知识点。
1) 学习类与对象的定义、声明及使用方法。
2) 学习具有不同属性的数据成员与成员函数的访问方式。
3) 理解构造函数和析构函数的定义与执行过程。
4) 学习定义和使用类的继承关系,定义派生类。
二、实验环境
写出程序编写时所使用的编译器、操作系统等。
编译器:Visual C++ 6.0.
操作系统:Windows XP.
三、实验内容与实验过程及分析
列出实验需要做的各个题目,并针对每个题目:
1. 写出关键代码(要求选出该题目最核心的代码并加注释);
2. 描述调试的过程、调试过程中所出现的现象及解决方法,给出题目最终运行结果;
3. 对该题目进行简短总结,写出该题目所涉及的知识点。
1) 下面是“平面上点”类的定义:
class CPoint
{
private:
int x, y;
static int nCount; // nCount用于保存点的个数
public:
CPoint(int px=0, int py=0);
CPoint(CPoint&);
~CPoint();
int GetX();
int GetY();
void SetX(int);
void SetY(int);
void ShowPoint();
};
请完成该类中各成员函数的定义。该类是一个基本的类。在编写该类时,要注意对静态成员nCount的操作,使其能够正确表示程序中点的个数。编完该类后,要在main()函数中进行测试,分别定义CPoint类的对象、指针、引用,对各成员函数进行调用。分析对静态成员的调用和一般成员的调用方式有什么不同。
1,本题目的核心代码:
int CPoint::nCount = 0; // 对nCount进行初始化,静态成员的调用
CPoint::CPoint(int px, int py) // 构造函数
{
x = px;
y = py;
nCount++; // 点的个数累加
}
CPoint::CPoint(CPoint& p) // 对构造函数进行拷贝
{
x = p.x;
y = p.y;
nCount++; // 点的个数继续累加
}
CPoint::~CPoint() // 析构函数
{
nCount--;
}
int CPoint::GetX()
{
return x;
}
int CPoint::GetY()
{
return y;
}
void CPoint::SetX(int px1) // 设置点的X坐标
{
x = px1;
}
void CPoint::SetY(int py1) // 设置点的Y坐标
{
y = py1;
}
void CPoint::ShowPoint() // 输出点的个数及点的坐标到屏幕
{
cout<<"点的个数为:"<<CPoint::nCount<<endl;
cout<<"平面点的坐标为:("<<CPoint::GetX()<<","<<CPoint::GetY()<<")"<<endl;
}
2,调试过程中所出现的现象及解决方法:
在调试时,程序不能运行没有运行成功,经过查阅资料后得知对静态成员的调用必须用类名加双冒号进行调用,把代码改成CPoint::nCount后,程序成功运行。
在构造函数的声明和定义中,都进行了变量的赋值,结果造成编译不通过,在去掉声明中的赋值后,才编译通过。
程序运行结果:
3,题目总结及题目所涉及的知识点:
通过本题学到了静态成员的调用方法以及如何构造、析构函数。
本题目主要涉及的知识点有:
1,构造函数、析构函数和拷贝。
2,静态成员的调用和类与对象的定义、声明及使用方法。
3, 拷贝函数和构造函数的编写。
4,具有不同属性的数据成员与成员函数的访问方式。
5,构造函数和析构函数的定义与执行过程。
2)下面是“平面上线段”类的定义:
class CLine
{
private:
CPoint pt1, pt2; //pt1和pt2分别代表该线段的起点和终点
public:
CLine();
CLine(int x1,int y1,int x2,int y2);
CLine(CPoint p1,CPoint p2);
double Distance(); //计算该线段长度的成员函数
void ShowLine();
};
请完成该类中各成员函数的定义。并利用VC调试工具观察含有组合关系类的构造函数和析构函数的执行情况。
1,本题目的核心代码:
public:
CLine(); //无参构造函数
CLine(int x1,int y1,int x2,int y2):pt1(x1,y1),pt2(x2,y2){} // 构造函数初始化列表
CLine(CPoint p1,CPoint p2):pt1(p1),pt2(p2){} // 构造函数初始化列表
double Distance(); //计算该线段长度的成员函数
void ShowLine();
};
double CLine::Distance() //计算线段的长度
{
double a,b;
a = (pt2.GetX() - pt1.GetX())*(pt2.GetX() - pt1.GetX());
b = (pt2.GetY() - pt1.GetY())*(pt2.GetY() - pt1.GetY());
return sqrt(a+b);
}
void CLine::ShowLine() //在屏幕输出线段长度
{
cout<<"线段的长度为:"<<CLine::Distance()<<endl;
}
2,调试过程中所出现的现象及解决方法:
在调试时,程序先执行nCount的构造函数,然后执行Cline的构造函数。
在使用初始化参数列表时,要根据构造函数里的参数变量名来编写参数列表。
程序运行结果:
3,题目总结及题目所涉及的知识点:
通过这个实验,了解到了如何运用初始化列表进行构造函数,它可以显示的调用基类成员,本题目涉及到的主要知识点是用初始化列表进行构造函数,组合类的声明和定义以及组合类构造函数的初始化过程。
3) 下面是“空间中点”类的定义:
class CThreePoint:public CPoint
{
private:
int z;
public:
CThreePoint();
CThreePoint(int, int, int);
int GetZ();
void SetZ(int pz);
virtual void ShowPoint();
};
请完成该类中各成员函数的定义。并利用VC调试工具观察含有继承关系类的构造函数和析构函数的执行情况。分析为什么要把ShowPoint()函数设置为虚函数?有什么作用?请在main()函数中做测试。
1,本题目的核心代码:
CThreePoint::CThreePoint(int px2, int py2, int pz2) // CThreePoint的构造函数
{
CPoint::SetX(px2);
CPoint::SetY(py2);
CThreePoint::SetZ(pz2);
}
CThreePoint::~CThreePoint(){} // CTrheePoint的析构函数
int CThreePoint::GetZ() // 获取并返回Z坐标的值
{
return z;
}
void CThreePoint::SetZ(int pz) // 对Z坐标的值进行设置
{
z = pz;
}
void CThreePoint::ShowPoint() // 屏幕输出点的坐标
{
cout<<"空间点的坐标为:("<<CPoint::GetX()<<","<<CPoint::GetY()<<","<<CThreePoint::GetZ()<<")"<<endl;
}
2,调试过程中所出现的现象及解决方法:
在调试过程中,程序首先执行基类的构造函数,然后在执行自己的构造函数。
程序运行结果:
3,题目总结及题目所涉及的知识点:
通过这个实验,了解到了:
1, 程序首先执行基类的构造函数,然后执行自己的构造函数,以及在继承关系中如何编写构造函数。
2, 派生类对象不能直接访问基类继承过来的私有成员。
3, 基类将函数声明为虚函数即可,派生类和函数的定义处可以没有关键字virtual.
本题目涉及的知识点有:定义和使用类的继承关系,定义派生类、派生类中构造函数的编写方法,和继承关系中构造函数的执行顺序。
4) 定义一个基类Animal,有私有整型成员变量age,构造其派生类dog,在其成员函数SetAge(int n)中直接给age赋值,看看会有什么问题,把age改为公有成员变量,还会有问题吗?把age改为保护成员变量呢?编程试试看。
1,本题目的核心代码:
class Animal
{
public:
int age;
};
class dog: public Animal
{
public:
int SetAge(int n)
{
age = 3;
}
};
2,题目总结及题目所涉及的知识点:
编写基类Animal时,成员变量age定义为私有的。构造派生类dog,在其成员函数SetAge(int n)中直接对age赋值时,会出现类似以下的错误提示:
error C2248:‘age’:can not access private member declared in class ‘Animal’
把age改为公有成员变量后重新编译就可以了。再把age改为保护成员变量步骤相同。
说明了派生类不能调用基类的私有成员变量的变量,而可以调用基类的公有成员和保护成员。设计的知识点有:派生类不能访问基类的私有成员,可以访问基类的保护和公有成员。
五、实验总结
对自己的实验的自我剖析,总结实验的心得体会,并提出实验的改进意见等。
在这次试验中,感觉自己的程序最难编写的地方就是类的构造函数,在经过仔细的查阅资料和询问同学后,终于熟练了构造函数的编写,从这次试验中我学到了很多C++的核心知识,利如函数的构造和析构函数,构造函数初始化列表,拷贝,派生类和基类的构造函数执行的先后顺序等。使我们在巩固基础的前提下游更大的提高。
对于本实验,虽然试验内容很少,但涵盖的知识点颇多,能让同学轻松的学到很多知识,但我感觉在给程序多加一些功能和达到更好的效果。能让我们在学到知识的同时,锻炼编写出色代码的能力。
六、思考题
回答实验要求的思考题,要将原题也写出来。
1) 构造函数和析构函数的作用是什么?
答:构造函数又分为
实例构造函数:实例构造函数用于创建和初始化实例。
私有构造函数:私有构造函数是一种特殊的实例构造函数。它通常用在只包含静态成员的类中。如果类具有一个或多个私有构造函数而没有公共构造函数,则不允许其他类(除了嵌套类)创建该类的实例。
静态构造函数:静态构造函数用于初始化类。在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类。
带参数的构造函数作用是为了来初始化某些值而设。
析构函数:析构函数用于销毁类的实例。
2) 什么是封装?类是如何进行封装的?
答:封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过 外部接口,一特定的访问权限来使用类的成员。通过封装使一部分成员充当类与外部的接口,而将其他的成员隐蔽起来,这样就达到了对成员访问权限的合理控制,使不同类之间的相互影响减少到最低限度,进而增强数据的安全性和简化程序的编写工作。
3) C++中有哪几种派生方式?每种方式的派生类对基类成员的继承和访问控制属性是什么样的?
答:C++中的派生方式有public 、private 、protected。
基类(父类)得私有成员,派生类(子类)都不能访问;
基类得公有成员,派生类得继承方式决定了其函数得形式;
基类得保护成员在派生类得公有继承中也是保护类型。
4) 派生类对象和基类对象是什么样的关系?派生类对象的构造函数和析构函数的执行顺序是怎样的?
答:派生类继承于基类。当用派生类定义一个对象时,除了继承时附加的函数和参数外,就是基类对象的函数和参数。首先执行派生类的构造函数在基类的构造函数之后执行,而析构函数正好相反。
5) 什么是多态?在C++语言中,是如何实现多态的?
答:多态,是面向对象的程序设计语言最核心的特征。多态,意味着一个对象有着多重特征,可以在特定的情况下,表现不同的状态,从而对应着不同的属性和方法。
在类的继承结构中,函数原型完全相同的函数,可以定义为虚函数。通过将类族里一致对外的接口函数定义为虚函数来实现。
七、参考文献
记录实验过程中主动查阅的纸质和电子文档等资料。
参考的资料:C++面向对象程序设计
第二篇:C实验报告格式样本
附件(四)
深 圳 大 学 实 验 报 告
课程名称: C程序设计
实验项目名称: 最简单的C程序设计
学院:
专业:
指导教师:
报告人: 学号: 班级:
实验时间: 20##年3月22日—4月4日
实验报告提交时间:2007年4月10日前
教务处制