仅供讨论、学习。
转载、使用请注明出处。
实验一
1.1. 输人并运行所给的参考程序1,并将程序中的注释部分也输人计算机,体会和理解程序的基本格式规范。
建立一个控制台应用程序项目baseforml,向其中添加一个源程序文件sum.cpp。按照所给的程序代码输入到计算机中,检查和调试程序,在确认没有发现错误之后,选择[Build]--[Build sum.exe]编译源程序,再选择[Build]-[Execute sum.exe]运行程序,并观察输出结果。若有问题,则需要重新检查程序。
#include
using namespace std;
int add(int a,int b);
int main() {
int x,y,sum;
cout<<"Enter two numbers:\n";
cin>>x>>y;
sum=add(x,y);
cout<<"The sum is:"<
运行效果:
1.2. 编写重载函数Maxl可分别求取两个整数,三个整数,两个双精度数,三个双精度数的最大值。
分别编写四个同名函数maxl,实现函数重载,在main()函数中测试函数功能。程序名:lab1_2.cpp。
#include
using namespace std;
int Max1(int a, int b);
int Max1(int a, int b, int c);
double Max1(double a, double b);
double Max1(double a, double b,double c);
int main () {
int max1=Max1(1,2);
int max2=Max1(1,2,3);
double max3=Max1(1.0,2.0);
double max4=Max1(1.0,2.0,3.0);
cout<<"the max number of (1,2) is: "<
运行效果:
1.3. 编写并测试3X3矩阵转置函数,使用数组保存3X3矩阵。
编写矩阵转置函数,输人参数为3X3整型数组,使用循环语句实现矩阵元素的行列对调,注意在循环语句中究竟需要对哪些元素进行操作,编写main ( )函数实现输入、输出。程序名:lab1_3.cpp。
#include
using namespace std;
void matrixTransposed(int matrix[3][3]);
int main() {
int matrix[3][3];
cout<<"Enter a 3x3 matrix, please. "<> matrix[i][j];
}
}
matrixTransposed(matrix);
cout<<"The transposed matrix is: "<
运行效果:
1.4. 使用动态内存分配生成动态数组来重新完成上题,使用指针实现函数的功能。
改写矩阵转置函数,参数为整型指针,使用指针对数组元素进行操作,在main ( )函数中使用new操作符分配内存生成动态数组。通过debug观察指针的内容及其所指的对象中的内容。程序名:lab1_4.cpp。
#include
using namespace std;
int** matrixTransposed(int **m,int row,int col);
int main() {
int row,col;
cout<<"Enter the row of the row*col matrix, please: "<>row;
cout<<"Enter the col of the row*col matrix, please: "<>col;
cout<<"Enter a "<>m[i][j];
}
}
//转置矩阵
int **mt=new int*[col];
for(int i=0; i
运行效果:
1.5. 编写程序,读写指定的文件,在每一行前加行号后,将结果输出到屏幕。
编写程序lab1_5.cpp,使用void main(int argc, char argv[])函数中的参数传递操作的文件名,定义ofstream的对象对文件进行操作,使用get()或getline()成员函数读入数据,使用输出流对象输出数据到屏幕。
#include
#include
#include
#include
using namespace std;
void printTxt(string file);
int main(int argc,char* argv[]) { //路径名不能有空格哦~~ 不然我会挂掉给你看~~
string filename=argv[1];
printTxt(filename);
return 0;
}
void printTxt(string file) {
ifstream infile;
infile.open(file.data()); //将文件流对象与文件连接起来
assert(infile.is_open()); //若失败,则输出错误消息,并终止程序运行
string c;
int i=0;
while (true) {
i++;
getline(infile,c);
if(infile.eof())
break;
cout<
运行效果:
实验二
2.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();
};
请完成该类中各成员函数的定义。
2.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调试工具观察含有组合关系类的构造函数和析构函数的执行情况。
2.3. 以成员函数的方式,重载题目1中的CPoint类的“+”运算符,返回的CPoint类对象的横纵坐标值分别等于原两点的横纵坐标值之和;以全局函数的方式重载CPoint类的“-”运算符,返回的CPoint类对象的横纵坐标值分别等于原两点的横纵坐标值之差。
2.4. 对于题目1中的CPoint类,重载“>>”运算符使得像cin等输入流对象能够写CPoint类对象,再重载“<<”运算符使得像cout等输出流对象能够输出CPoint类对象。
#include
#include
using namespace std;
//平面上的点类
class CPoint {
private:
int x, y;
public:
static int nCount; // nCount用于保存点的个数
CPoint(int px=0, int py=0) { //构造函数
x=px;
y=py;
nCount++;
};
CPoint(CPoint& p) { //拷贝构造
x=p.x;
y=p.y;
nCount++;
// cout<<"copy constructor is invoked."<"<>(istream& is, CPoint& p);
friend ostream& operator<<(ostream& os, CPoint& p);
};
int CPoint::nCount = 0;
//平面上的直线类
class CLine {
private:
CPoint pt1, pt2; //pt1和pt2分别代表该线段的起点和终点
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() { //计算该线段长度的成员函数
int x_x=pt1.GetX() -pt2.GetX() ;
int y_y=pt1.GetY() -pt2.GetY() ;
double dis=pow((double)(pow(x_x,2)+pow(y_y,2)),0.5);
return dis;
};
void ShowLine() {
cout<<"<"<"
<<"-->"
<<"<"<"
<GetX());
sumPoint.SetY(pt.GetY() +this->GetY());
return sumPoint;
}
CPoint operator- (CPoint pt1, CPoint pt2) { //全局重载-
CPoint difPoint;
difPoint.SetX(pt1.GetX() -pt2.GetX() );
difPoint.SetY(pt1.GetY() -pt2.GetY() );
return difPoint;
}
istream& operator>>(istream& is, CPoint& p) { //成员函数重载》
is>>p.x >>p.y;
return is;
}
ostream& operator<<(ostream& os, CPoint& p) { //成员函数重载《
os<<"<"<";
return os;
}
int main() {
//验证点类的正确实现
CPoint a(1,2),b(3,4),c(a);
cout<<"the first point is:a";
a.ShowPoint() ;
cout<<"the second point is:b";
b.ShowPoint() ;
cout<<"the third point is:c";
a.ShowPoint() ;
cout<<"the nCount is:"<>overloadCP;
cout<<"Your point is: ";
cout<
运行效果:
实验三
3.1. 使用实验2中的CPoint类,定义 “空间中点”类如下:
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()函数中做测试。
编程时重点分析CThreePoint类的构造函数如何编写,并通过调试运行查看在继承关系中构造函数的执行顺序。
#include
using namespace std;
//平面上的点类
class CPoint {
private:
int x, y;
public:
static int nCount; // nCount用于保存点的个数
CPoint(int px=0, int py=0) { //构造函数
x=px;
y=py;
nCount++;
};
CPoint(CPoint& p) { //拷贝构造
x=p.x;
y=p.y;
nCount++;
// cout<<"copy constructor is invoked."<"<>(istream& is, CPoint& p);
friend ostream& operator<<(ostream& os, CPoint& p);
};
int CPoint::nCount = 0;
//空间中的点类
class CThreePoint:public CPoint {
private:
int z;
public:
CThreePoint() {};
CThreePoint(int px=0, int py=0, int pz=0) {
SetX(px);
SetY(py);
z=pz;
};
int GetZ() {
return z;
};
void SetZ(int pz) {
z=pz;
};
virtual void ShowPoint() { //此处virtual关键字可省略。不过习惯上不省略,方便阅读代码
cout<<"<"<"<ShowPoint();
p=&b;
cout<<"基类指针指向派生类函数示例:"<ShowPoint();
return 0;
}
运行效果:
3.2. 下面是一个“Shape”基类的定义:
enum ColorType{White, Black, Red, Green, Blue, Yellow, Magenta, Cyan};
//为图形形状定义Shape基类
class Shape
{
protected:
ColorType color;
public:
Shape(ColorType c);
virtual void draw();
};
使用Shape类和CPoint类设计一个可在屏幕上作图的简单实例,要求是不必真正在屏幕上实现作图,只是有一个示意即可。例如:画一个矩形,不必真正画出矩形,只需输出一句话:“This is a rectangle!”即可。要求可画线段、矩形和圆形。要用到继承,虚函数,多态,数据的封装,构造函数的实现等等各种面向对象程序设计的特性。
可以使用CPoint类,指明屏幕上特定点的位置,其他的各个类都可以使用它。再使用基类Shape类,然后在Shpae类的基础上派生出各种类,如直线类Cline(可简单修改一下实验2中的Cline类),矩形类CRectangle,圆类CCircle。注意要把每个类的特征用最简单的方式表示出来。
#include
#include
using namespace std;
//平面上的点类
class CPoint {
private:
int x, y;
public:
static int nCount; // nCount用于保存点的个数
CPoint(int px=0, int py=0) { //构造函数
x=px;
y=py;
nCount++;
};
CPoint(CPoint& p) { //拷贝构造
x=p.x;
y=p.y;
nCount++;
// cout<<"copy constructor is invoked."<"<>(istream& is, CPoint& p);
friend ostream& operator<<(ostream& os, CPoint& p);
};
int CPoint::nCount = 0;
enum ColorType {White, Black, Red, Green, Blue, Yellow, Magenta, Cyan};
//为图形形状定义Shape基类
class Shape {
protected:
ColorType color;
public:
Shape(ColorType c) {
color=c;
};
virtual void draw() {
};
virtual string getColor(ColorType c) {
switch(c) {
case 0:
return "White";
case 1:
return "Black";
case 2:
return "Red";
case 3:
return "Green";
case 4:
return "Blue";
case 5:
return "Yellow";
case 6:
return "Magenta";
case 7:
return "Cyan";
default:
return "";
}
};
};
class Cline:public Shape {
private:
CPoint p0,p1;
public:
Cline(ColorType c,int x0,int y0,int x1,int y1)
:Shape(c),p0(x0,y0),p1(x1,y1) {};//初始化列表,用于继承
virtual void draw() {
cout<<"This is a line. And it's color is "<--><"
<."<--><"<-->"<<"<"<--><"
<."<."<draw();
}
return 0;
}
运行效果:
3.3. 定义一个车(vehicle)基类,具有MaxSpeed、Weight等成员变量,Run、Stop等成员函数,由此派生出自行车(bicycle)类、汽车(motorcar)类。自行车(bicycle)类有高度(Height)等属性,汽车(motorcar)类有座位数(SeatNum)等属性。从bicycle和motorcar派生出摩托车(motorcycle)类,它们都有Run、Stop等成员函数。观察虚函数的作用。在继承过程中,注意把vehicle设置为虚基类。如果不把vehicle设置为虚基类,会有什么问题?编程试试看。
编写程序定义一个车(vehicle)基类,有Run、Stop等成员函数,由此派生出自行车(bicycle),汽车(motorcar),从bicycle和motorcar派生出摩托车(motorcycle),它们都有Run、Stop等成员函数。在main()函数中定义vehicle,bicycle,motorcar,motorcycle的对象,调用其Run()、Stop() 函数,观察其执行情况。 再分别用vehicle类型的指针来调用这几个对象的成员函数,看看能否成功;把Run、Stop定义为虚函数,再试试看。
#include
using namespace std;
class vehicle {
public:
double MaxSpeed,Weight;
virtual void Run() {
cout<<"好,跑起来了!速度是:"<Run();
pt->Stop();
pt=&b;
pt->Run();
pt->Stop();
pt=&mcar;
pt->Run();
pt->Stop();
pt=&mb;
pt->Run();
pt->Stop();
return 0;
}
运行效果:
实验四
4.1. 编写一个函数模板,要求它返回两个值中的最小者。但同时要确保正确处理字符串。
函数模板的原型可定义为:template
#include
#include
using namespace std;
template
T min(T& a, T& b) {
return (a
运行效果:
4.2. 以下是一个整数栈类的定义:
const int SIZE = 100;
class Stack
{
public:
Stack();
~Stack();
void Push(int n);
int Pop();
private:
int stack[SIZE];
int tos;
};
编写一个栈的类模板(包括其成员函数定义),以便为任何类型的对象提供栈结构数据操作。并在应用程序中创建整数栈、字符栈和浮点数栈,提供一些数据进行进栈、退栈和打印操作的测试。
根据整数栈的定义,可抽象出的栈类模板为:
template
class Stack{
public:
Stack();
~Stack();
void Push(T& n);
T Pop();
private:
static const int SIZE;
T* stack;
int tos;
};
这里需要将该模板中的各成员函数进行定义即可。tos是栈顶位置,Push()为压栈操作,Pop()为弹栈操作,要在这两个操作中分别考虑栈的长度和栈是否为空。最后,要在main函数中对编写的栈类模板进行测试。
#include
#include
#include
#include
#include
using namespace std;
template
class Stack {
private:
vector elems; // 元素
public:
void push(T const&); // 入栈
void pop(); // 出栈
T top() const; // 返回栈顶元素
bool empty() const { // 如果为空则返回真。
return elems.empty();
}
};
template
void Stack::push (T const& elem) {
// 追加传入元素的副本
elems.push_back(elem);
}
template
void Stack::pop () {
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
// 删除最后一个元素
elems.pop_back();
}
template
T Stack::top () const {
if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
// 返回最后一个元素的副本
return elems.back();
}
int main() {
try {
Stack intStack; // int 类型的栈
Stack charStack; // char 类型的栈
Stack floatStack; //float 类型的栈
// 操作 int 类型的栈
intStack.push(7);
cout << "打印intStack栈顶元素:"<
运行效果:
4.3. 编写一程序,让用户自由地从键盘上输入整数,直到输入数字0时结束。把用户输入的数据保存在模板类Vector
a) 仅使用Vector
b) 使用迭代器自己编程输出;
c) 使用STL提供的通用算法for_each进行输出。
实现该题目时,首先定义模板类Vector
#include
#include
#include
using namespace std;
void show(int n){
cout< a;
int n=0;
do {
cin>>n;
a.push_back(n);
} while(n!=0);
for(int x=0; xa[y]) {
int z=a[x];
a[x]=a[y];
a[y]=z;
}
}
}
for(int x=0; x::iterator start=a.begin();//第二种方式利用Vector的迭代器进行输出
vector::iterator end=a.end();
while(start!=end) {
cout<<*start<<" ";
start++;
}
cout<
运行效果:
4.4. 以下是一个List类模板的定义:
template
public:
List(); //构造函数
void Add(T&); //在Link表头添加新结点
void Remove(T&); //在Link中删除含有特定值的元素
T* Find(T&); //查找含有特定值的结点
void PrintList(); // 打印输出整个链表
~List();
protected:
struct Node{
Node* pNext;
T* pT;
};
Node *pFirst; //链首结点指针
};
完成对上述List类模板含有的各成员函数的定义。然后定义一个简单的Student类,并利用编写的List类模板对一个班级的学生进行动态管理。(根据自己的能力选做)。
要编写出这个程序,要理解Link类模板中各数据成员的含义。pFirst代表链表首指针,Node代表链表的一个结点,pT为指向该结点对应数据的指针,理解这点非常重要。
#include
#include
#include
#include
#include
#include "math.h"
using namespace std;
template class List {
public:
List() { //构造函数
pFirst = NULL;
}
void Add(T& t) { //在List表头添加新结点
if(pFirst == NULL) {
pFirst = new Node;
*(pFirst->pT) = t;
} else {
Node* last = pFirst;
while((last->pNext)!=NULL) {
last=last->pNext;
};
Node* pNewNode = new Node;
*(pNewNode->pT) = t;
pNewNode->pNext = NULL;
last->pNext = pNewNode;
}
}
void Remove(T& t) { //在List中删除含有特定值的元素
Node* pNode = pFirst;
if(*(pNode->pT) == t) {
pFirst = pFirst->pNext;
delete pNode;
return;
}
while(pNode != NULL) {
Node* pNextNode = pNode->pNext;
if(pNextNode!=NULL) {
if(*(pNextNode->pT) == t) {
pNode->pNext = pNextNode->pNext;
delete pNextNode;
return;
}
} else
return;//没有相同的
pNode = pNode->pNext;
}
}
T* Find(T& t) { //查找含有特定值的结点
Node* pNode = pFirst;
while(pNode != NULL) {
if(*(pNode->pT) == t) {
return pNode->pT;
}
pNode = pNode->pNext;
}
return NULL;
}
void PrintList() { // 打印输出整个链表
if(pFirst == NULL) {
cout<<"null..."<pT)<pNext;
}
}
~List() {
Node* pNode = pFirst;
while(pNode != NULL) {
Node* pNextNode = pNode->pNext;
delete pNode;
pNode = pNextNode;
}
}
protected:
struct Node {
Node* pNext;
T* pT;
Node() {
pNext = NULL;
pT = new T;
}
~Node() {
delete pT;
}
};
Node *pFirst; //链首结点指针
};
class Student {
public:
char id[20]; //学号
char name[20]; //姓名
int score; //成绩
Student() {
}
~Student() {
}
Student(const char* pid, const char* pname, int _score) {
strcpy(id, pid);
strcpy(name, pname);
score = _score;
}
bool operator==(const Student& stu) {
return strcmp(id, stu.id) == 0 && strcmp(id, stu.id) == 0 && score==stu.score;
}
Student& operator=(const Student& stu) {
strcpy(id, stu.id);
strcpy(name, stu.name);
score = stu.score;
}
friend ostream& operator<< (ostream &out,const Student& stu);
};
ostream & operator<< (ostream &out,const Student& stu) {
out<<"id:"< worldCup;
cout<<"Before the adding:"<
运行效果:
欢迎讨论不同的实现方式,及批评指正代码实现中的不足之处~