东北大学-C++选修课-课程实验总结

    仅供讨论、学习。

    转载、使用请注明出处。

实验一

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:"<

运行效果:

东北大学-C++选修课-课程实验总结_第1张图片

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: "<

运行效果:

东北大学-C++选修课-课程实验总结_第2张图片

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: "<

运行效果:

东北大学-C++选修课-课程实验总结_第3张图片

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

运行效果:

东北大学-C++选修课-课程实验总结_第4张图片

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<

运行效果:

东北大学-C++选修课-课程实验总结_第5张图片

 

实验二

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<

运行效果:

东北大学-C++选修课-课程实验总结_第6张图片

 

实验三

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;
}

运行效果:

东北大学-C++选修课-课程实验总结_第7张图片

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;
}

运行效果:

东北大学-C++选修课-课程实验总结_第8张图片

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;
}

运行效果:

东北大学-C++选修课-课程实验总结_第9张图片

实验四

4.1. 编写一个函数模板,要求它返回两个值中的最小者。但同时要确保正确处理字符串。

    函数模板的原型可定义为:template T min(T&, T&),为了同时要确保正确处理字符串,而字符串不能用“<”来比较,所以还需要特别定义函数:char* min(char* a, char* b)。另外,要在main函数中对自己编写的模板进行测试。

#include
#include
using namespace std;

template
T min(T& a, T& b) {
	return (a

运行效果:

东北大学-C++选修课-课程实验总结_第10张图片

 

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栈顶元素:"<

运行效果:

东北大学-C++选修课-课程实验总结_第11张图片

 

4.3. 编写一程序,让用户自由地从键盘上输入整数,直到输入数字0时结束。把用户输入的数据保存在模板类Vector定义的对象中,并对用户输入的所有数进行排序输出。在向显示器进行输出时,要求用一下3种方式实现:

a) 仅使用Vector的相关成员函数,不使用迭代器进行输出;

b) 使用迭代器自己编程输出;

c) 使用STL提供的通用算法for_each进行输出。

实现该题目时,首先定义模板类Vector的一个对象,利用该对象进行对用户输入数据的操作。在进行数据输出时,第一种方式考虑采用类似于数组的随机访问方法,第二种方式利用Vector的迭代器进行输出,第二种方式则利用STL通用算法for_each进行实现,也可以才用copy函数进行实现。

#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<

运行效果:

东北大学-C++选修课-课程实验总结_第12张图片

 

4.4. 以下是一个List类模板的定义:

template class List{

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:"<

运行效果:

东北大学-C++选修课-课程实验总结_第13张图片

 

欢迎讨论不同的实现方式,及批评指正代码实现中的不足之处~

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(About,C++)