面向对象程序设计第三次上机作业Debug心路历程

面向对象程序设计第三次上机作业Debug心路历程

前言

由于西安疫情不可抗力因素,期中考试被迫推迟

请添加图片描述

世界第一拉扯.icu没有拉扯!新校长万岁!!!

原本定于期中考试之后再写的OOP上机作业被挪到了这个周(请叫我时间管理大师

然后就有了,在写屎山代码中的一些奇奇怪怪的bug

新手上路,如有错误欢迎指出

1.Container类

题目描述:

定义抽象基类 Container, 至少含有2个纯虚函数:getVolume, getArea,分别实现计算Container体积,计算面积的功能。由它派生出3个派生类:Sphere(球体),Cylinder(圆柱体)、Cube(正方体),派生类需要实现基类中的纯虚函数,实现动态多态。

要求:

1.绘制与本例相关的UML图
2.每个类的头文件和成员方法实现文件分开
3.写一个名为main.cpp的文件,在其中验证动态多态的效果;
4.利用基于vector容器(自行查阅资料,了解vector容器的用法),存储与子类对象相关的数据,通过对容器内元素进行遍历,调用getVolume, getArea,体现动态多态

迅速标记关键词:抽象基类、纯虚函数、动态多态

那就先写个Container的基类

//container.h
class Container {
public:
	virtual double getVolume()=0;
	virtual double getArea()=0;
	virtual void display()=0;
};

看起来并没有什么毛病(实际有一个非常致命的问题,但在目前还不影响)

这里运用了虚函数,老师上课讲过(照着PPT抄过来就是了

接着实现成员方法

//container.cpp
#include"container.h"
#include<iostream>
using namespace std;
double Container::getArea(){
	return 0;
}
double Container::getVolume(){
	return 0;
}
void Container::display(){
	cout << "Container volume: " << getVolume() << endl;
	cout << "Container area: " << getArea()<<endl;
}

自我感觉良好,接着往下写

//sphere.h
#include"container.h"
class Sphere :public Container {
private:
	double radius;
public:
	Sphere(double r) {
		radius = r;
	}
	double getVolume();
	double getArea();
	void display();
};

是的,依旧是看起来没什么问题,但是同样的致命错误,目前不影响

//sphere.cpp
#include"sphere.h"
#include<iostream>
using namespace std;
double Sphere::getVolume(){
	return 4.0 / 3 * 3.14 * radius * radius * radius;
}
double Sphere::getArea(){
	return 4 * 3.14 * radius * radius;
}
void Sphere::display() {
	cout << "Sphere volume: " << getVolume() << endl;
	cout << "Sphere area: " << getArea() << endl;
}

我这个人有个毛病,不喜欢全写完代码再找bug,于是我在写完Sphere类之后就建了main.cpp来测试我的基类和派生类Sphere有无问题

//main.cpp
#include"container.h"
#include"sphere.h"
#include<iostream>
using namespace std;
void calculator(Container* s) {
	s->display();
}
int main() {
	Container* s1 = new Sphere(4);
	calculator(s1);
	delete s1;
	return 0;
}

之前说了那个致命问题在目前是不影响的, 所以显然,在测试的时候也没有问题,正常输出了Sphere的体积Volume和面积Area

在这里插入图片描述

没毛病,很简单,喜大普奔,转战第二个派生类Cylinder

//cylinder.h
#include"container.h"
class Cylinder :public Container {
private:
	double radius,height;
public:
	Cylinder(double r, double h) {
		radius = r;
		height = h;
	}
	double getVolume();
	double getArea();
	void display();
};
//cylinder.cpp
#include"cylinder.h"
#include<iostream>
using namespace std;
double Cylinder::getVolume(){
	return 3.14 * radius * radius * height;
}
double Cylinder::getArea(){
	return 3.14 * radius * radius * 2 + 3.14 * 2 * radius * height;
}
void Cylinder::display(){
	cout << "Cylinder volume: " << getVolume() << endl;
	cout << "Cylinder area: " << getArea() << endl;
}

放到main.cpp中测试

//main.cpp
#include"container.h"
#include"sphere.h"
#include"cylinder.h"
#include<iostream>
using namespace std;
void calculator(Container* s) {
	s->display();
}
int main() {
	Container* s1 = new Sphere(4);
	Container* s2 = new Cylinder(4,5);
	calculator(s1);
	calculator(s2);
	delete s1;
	delete s2;
	return 0;
}

好的,之前说过的问题在此时暴露了
在这里插入图片描述
在这里插入图片描述

根本问题是什么,是代码为C2011的类型重定义

确实最后在main.cpp中引用头文件的时候Container类的定义被重复引用了两次

此时我就想着那把cylinder.h引用container.h改成引用sphere.h应该就能解决这个问题,然后再main.cpp中只引用cylinder.h

后来转念一想,当我写cube的时候,那我是不是应该引用cylinder.h,然后再main.cpp中引用cube.h,天哪,这也太麻烦了,一定是哪里出了问题

在这里插入图片描述
[详细编译器错误戳这里]

#pragma once 好熟悉的东西

哦是我每次新建.h文件式都要删掉的那一行

删掉!!!我为什么要把他删掉!!!

于是在每一个.h文件中重新写上

#pargma once

终于没问题
喜大普奔2.0

趁热打铁完成cube类

//cube.h
#pragma once
#include"container.h"
class Cube :public Container {
private:
	double length;
public:
	Cube(double l) {
		length = l;
	}
	double getVolume();
	double getArea();
	void display();
};

//cube.cpp
#include"cube.h"
#include<iostream>
using namespace std;
double Cube::getVolume() {
	return length * length * length;
}
double Cube::getArea() {
	return 6 * length * length;
}
void Cube::display() {
	cout << "Cube volume: " << getVolume() << endl;
	cout << "Cube area: " << getArea() << endl;
}

最后附上完整的main.cpp、运行结果以及UML图

//main.cpp
#include"container.h"
#include"sphere.h"
#include"cylinder.h"
#include"cube.h"
#include<iostream>
using namespace std;
void calculator(Container* s) {
	s->display();
}
int main() {
	Container* s1 = new Sphere(4);
	Container* s2 = new Cylinder(4,5);
	Container* s3 = new Cube(2.5);
	calculator(s1);
	calculator(s2);
	calculator(s3);
	delete s1;
	delete s2;
	delete s3;
	return 0;
}

在这里插入图片描述
请添加图片描述

小结

本题完成的尚可,完成了要求1、2、3,唯一不足的是没有使用vector容器,不过在下面的题中运用到了,满分10分的话给自己打个8分吧!

2.Matrix类

接下来转战本次上次作业中最折磨本人的一道题

请添加图片描述

首先在这里感谢zeroy同学为我答疑解惑

题目描述:

定义 矩阵类Matrix,包含整数型私有成员变量 row 和 col,分别代表矩阵的行数和列数。矩阵元素为float类型,且存储于通过new 操作符获取的 一维数组,定义该类的 构造函数、拷贝构造函数、析构函数,重载 赋值运算符=、加法运算符+和乘法运算符* ,使之实现矩阵加法和乘法运算;重载<<和>>运算符,使之能用于该矩阵的输入和输出。
矩阵类Matrix需要实现一个静态成员函数randomPopulate() , 实现一个矩阵元素随机填充方法,便于测试(如此无需手动输入元素)

迅速标记关键词:new 操作符、运算符重载

后来又同学在群里提问了关于静态成员函数的问题,于是题目变成了这样

定义矩阵类 Matrix,包含整数型私有成员变量 row 和 col,分别代表矩阵的行数和列数。矩阵元素为float类型,且存储于通过new 操作符获取的一维数组,定义该类的构造函数、拷贝构造函数、析构函数,重载赋值运算符=、加法运算符+和乘法运算符*,使之实现矩阵加法和乘法运算;重载<<和>>运算符,使之能用于该矩阵的输入和输出。
矩阵类Matrix需要实现一个静态成员函数randomPopulate(), 实现一个矩阵元素随机填充方法,便于测试(如此无需手动输入元素) 原题目描述中要求:“矩阵类Matrix需要实现一个静态成员函数randomPopulate()”,现订正为:矩阵类Matrix需要实现一个成员函数randomPopulate() 之所以要求定义这么一个函数,是为了方便对Matrix类进行测试。如果有同学觉得有其他更好更方便的测试手段,例如:手动输入、读取文件等,也是可以的。只要有助于测试Matrix类能正确工作即可。

首先先定义Matrix类

class Matrix {
public:
	int row, col;
	float* arr;
	Matrix() {
		row = 0;
		col = 0;
		arr = new float[row * col];
	}

	Matrix(int r, int c) {
		row = r;
		col = c;
		arr = new float[row * col];
	}

	Matrix(const Matrix& A) {
		row = A.row;
		col = A.col;
		arr = new float[row * col];
		for (int i = 0; i < row * col; i++) {
			arr[i] = A.arr[i];
		}
	}

	void operator =(const Matrix& A) {
		row = A.row;
		col = A.col;
		arr = new float[row * col];
		for (int i = 0; i < row * col; i++) {
			arr[i] = A.arr[i];
		}
	}

	~Matrix() {
		delete[]arr;//delete申请的堆资源
	}

	friend Matrix operator+(const Matrix& A, const Matrix& B);
	friend Matrix operator*(const Matrix& A, const Matrix& B);
	friend istream& operator>>(istream& in, Matrix& A);
	friend ostream& operator<<(ostream& out, Matrix& A);
};

然后是重载运算符的操作

Matrix operator+(const Matrix& A, const Matrix& B) {
	Matrix C;
	for (int i = 0; i < A.row * A.col; i++) {
		C.arr[i] = A.arr[i] + B.arr[i];
	}
	return C;
}

Matrix operator*(const Matrix& A, const Matrix& B) {
	Matrix C;
	float result = 0;
	for (int i = 0; i < A.row;  i++) {
		for (int j = 0; j <B.col; j++) {
			for (int k = 0; k < A.col; k++) {
				result += A.arr[i * A.col + k] * B.arr[k * B.col + j];
			}
			C.arr[i * C.col + j] = result;
			result = 0;
		}
	}
	return C;
}

istream& operator>>(istream& in, Matrix& A) {
	in >> A.row >> A.col;
	for (int i = 0; i < A.row; i++) {
		for (int j = 0; j < A.col; j++) {
			in >> A.arr[i * A.col + j];
		}
	}
	return in;
}

ostream& operator<<(ostream& out, Matrix& A) {
	out << "row: "<<A.row << " col: " << A.col << endl;
	for (int i = 0; i < A.row; i++) {
		for (int j = 0; j < A.col; j++) {
			out << A.arr[i * A.col + j] << " ";
		}
		out << endl;
	}
	return out;
}

最后是main函数

int main() {
	Matrix A, B, C, D, E;
	cin >> A;
	cin >> B;
	cin >> C;
	D = A + B;
	cout << D << endl;
	E = A * C;
	cout << E << endl;
	A.~Matrix();
	B.~Matrix();
	C.~Matrix();
	D.~Matrix();
	E.~Matrix();
	return 0;
}

当然,出问题了

咨询了zeroy同学,得到的结果是
请添加图片描述
请添加图片描述请添加图片描述

好有道理!

但是

请添加图片描述

请添加图片描述
好人一生平安

改了

但没完全改
请添加图片描述
请添加图片描述
请添加图片描述

我裂开了!!!

VScode 是好的,VS上就不行

请添加图片描述
请添加图片描述
在这里插入图片描述请添加图片描述
请添加图片描述请添加图片描述
请添加图片描述
所以,其实一切问题出在了我对指针运用的不熟练上,最原始的问题是拷贝构造函数没有分配内存。

经历了一天又一个上午的折磨,这个代码终于能正常跑了

附上能正常运行的代码以及与运行结果

//main.cpp
#include<iostream>
using namespace std;
class Matrix {
public:
	int row, col;
	float* arr;
	Matrix() {
		row = 0;
		col = 0;
		arr = new float[row * col];
	}

	Matrix(int r, int c) {
		row = r;
		col = c;
		arr = new float[row * col];
	}

	Matrix(const Matrix& A) {
		row = A.row;
		col = A.col;
		arr = new float[row * col];
		for (int i = 0; i < row * col; i++) {
			arr[i] = A.arr[i];
		}
	}

	void operator =(const Matrix& A) {
		row = A.row;
		col = A.col;
		arr = new float[row * col];
		for (int i = 0; i < row * col; i++) {
			arr[i] = A.arr[i];
		}
	}

	~Matrix() {
		delete[]arr;//delete申请的堆资源
	}

	friend Matrix operator+(const Matrix& A, const Matrix& B);
	friend Matrix operator*(const Matrix& A, const Matrix& B);
	friend istream& operator>>(istream& in, Matrix& A);
	friend ostream& operator<<(ostream& out, Matrix& A);
};

Matrix operator+(const Matrix& A, const Matrix& B) {
	Matrix C = Matrix(A.row, A.col);
	for (int i = 0; i < A.row * A.col; i++) {
		C.arr[i] = A.arr[i] + B.arr[i];
	}
	return C;
}

Matrix operator*(const Matrix& A, const Matrix& B) {
	Matrix C = Matrix(A.row, B.col);
	float result = 0;
	for (int i = 0; i < A.row; i++) {
		for (int j = 0; j < B.col; j++) {
			for (int k = 0; k < A.col; k++) {
				result += A.arr[i * A.col + k] * B.arr[k * B.col + j];
			}
			C.arr[i * C.col + j] = result;
			result = 0;
		}
	}
	return C;
}

istream& operator>>(istream& in, Matrix& A) {
	in >> A.row >> A.col;
	A = Matrix(A.row, A.col);
	for (int i = 0; i < A.row; i++) {
		for (int j = 0; j < A.col; j++) {
			in >> A.arr[i * A.col + j];
		}
	}
	return in;
}

ostream& operator<<(ostream& out, Matrix& A) {
	out << "row: " << A.row << " col: " << A.col << endl;
	for (int i = 0; i < A.row; i++) {
		for (int j = 0; j < A.col; j++) {
			out << A.arr[i * A.col + j] << " ";
		}
		out << endl;
	}
	return out;
}

int main() {
	Matrix A, B, C, D, E;
	cin >> A;
	cin >> B;
	cin >> C;
	D = A + B;
	cout << D << endl;
	E = A * C;
	cout << E << endl;
	return 0;
}

请添加图片描述
小结

其实写这个题的时候还出了很多问题,比如我的重载运算符,在编译器里总是有语法问题,然后关掉vs再打开又可以了,就很头疼,但最后在同学的帮助下还是完成啦!!!

满分10分给自己打6.5分,缺点是还是用的手动输入,没有写一个函数来完成。

3.Student 类

这个题其实完成的还是比较顺利的,基本没有出大问题

题目描述:

创建一个存有学生信息的文本型文件 student_info.txt,包含至少 10 名学生信息,该文件
格式如下:
姓名 性别 学号 成绩
Alice F 西电格式学号 90
Bob M 西电格式学号 87

定义类 Student,声明非静态私有成员变量:姓名、性别、学号、成绩,声明静态成员变
量:学生总人数和总成绩、定义静态成员函数get_average,支持计算所有学生的平均成绩。
该类需重载<<操作符,支持对 Student 类对象的格式化输出(例如:每个属性域宽 15, 各属性均采用左对齐等)。Student 类的其他成员变量、成员函数可按需求自行设计添加。
编写一个普通函数 student_info_parser(string file_name, vector<Student> &students),读取student_info.txt,填充存储学生类对象的容器 students
创建主函数文件 main.cpp,测试上述要求功能的正确性。

这个题,跟上学期大一的时候那个程序设计基础的有个题型很像,只不过之前那个是用C语言写的文件读写,这个使用C++写,并且有这个东西

考察的几乎是一样的

//student.h
#pragma once
#ifndef _STUDENT_H
#define _STUDENT_H

#include<iostream>
#include<fstream>
#include<string>
#include<cstdlib>
#include<vector>
#include<iomanip>
using namespace std;

class Student {
private:
	string name;
	char sex;
	string number;
	double score;
	static int totalAmount;//静态成员变量:总人数
	static double totalScore;//静态成员变量:总成绩

public:
	Student();
	Student(string n, char s, int num, double sco);
	static double get_average();//静态成员函数:计算所有学生的平均成绩

	friend void student_info_parser(string file_name, vector<Student>& students);
	friend ostream& operator<<(ostream& os, const Student& stu);
};
#endif
//student.cpp
#include"student.h"
using namespace std;

Student::Student() {

}

Student::Student(string n, char s, int num, double sco) {
	name = n;
	sex = s;
	number = num;
	score = sco;
}

double Student::get_average() {
	return totalScore / totalAmount;
}

//对静态成员变量进行初始化
int Student::totalAmount = 0;
double Student::totalScore = 0;

//重载<<操作符,对Student类对象的格式化输出(格式:左对齐,姓名、性别、学号、成绩的域宽分别为10,6,15,8
ostream& operator<<(ostream& os, const Student& stu) {
	os << setiosflags(ios::left) << setw(10) << stu.name << " " << setw(6) << stu.sex << " " << setw(15) << stu.number << " " << setw(8) << stu.score;
	return os;
}

void student_info_parser(string file_name, vector<Student>& students) {
	fstream fstrm;
	Student stu;
	fstrm.open("student_info.txt", ios::in);
	if (!fstrm) cout << "Open Error" << endl;
	while (fstrm >> stu.name) {
		fstrm >> stu.sex;
		fstrm >> stu.number;
		fstrm >> stu.score;
		students.push_back(stu);
		stu.totalAmount++;
		stu.totalScore += stu.score;
	}
	cout << "The number of student is " << stu.totalAmount << endl;
	fstrm.close();
}
//main.cpp
#include"student.h"
using namespace std;
int main() {
	Student stu;
	vector<Student> students;
	student_info_parser("student_info.txt", students);
	for (int i = 0; i < students.size(); i++) {
		cout << students[i] << endl;
	}
	cout << "The average score is " << stu.get_average() << endl;
	return 0;
}

student_info.text文件
请添加图片描述

写这个题的时候,最后纠结的是把txt文件放在哪里,一开始放在了这

请添加图片描述
然后就得到了这个运行结果

在这里插入图片描述

显然不对

然后觉得应该跟源文件放在一起

最后放在了这里

终于对了

附上运行结果

请添加图片描述
小结

题目完成的很顺利,也基本完成了老师的要求,满分10分给自己打9分!

4.文件流

同样非常顺利的一个题,上课好好听,看看PPT就能写出来

题目描述:

设计一个用文件流方式完成下面操作:
生成一个 6 × 6 的矩阵 A,其元素为 [0,1] 之间的双精度数。
(a)将其按矩阵形式写入到一个文本文件 fout01.txt 中;
(b) 将其写入到一个二进制文件 fout01.dat 中;
(c) 再从文件 fout01.dat 中读取前 12 个数据(双精度),构成一个 2 × 6 的矩阵 B,并将 B 按行输出

直接附上代码

\\main.cpp
#include<iostream>
#include<fstream>
using namespace std;

double getRand() {
	int number = rand() % 101;
	return number / 100.0;
}

int main() {
	//生成6*6个双精度数存入二维数组
	double arr[6][6]={0};
	for (int i = 0; i < 6; i++) {
		for (int j = 0; j < 6; j++) {
			arr[i][j] = getRand();
		}
	}

	fstream fstrm;
	fstrm.open("fout01.txt", ios::out);
	for (int i = 0; i < 6; i++) {
		for (int j = 0; j < 6; j++) {
			fstrm << arr[i][j] << " ";
		}
		fstrm << endl;
	}
	fstrm.close();

	fstrm.open("fout01.dat", ios::out | ios::binary);
	fstrm.write((char*)&arr, sizeof(arr));
	fstrm.close();

	double B[12];
	fstrm.open("fout01.dat", ios::in | ios::binary);
	fstrm.read((char*)&B, sizeof(B));
	fstrm.close();

	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 6; j++) {
			cout << B[6 * i + j] << " ";
		}
		cout << endl;
	}

	return 0;
}

中间出的小插曲有两个,一个是一开始定义的双精度二维数组没有赋值导致内存引起的错误,第二个是因为打字的问题文件名打的不一样导致的运行错误,最后改好就很OK

附上运行结果以及相关文件

在这里插入图片描述

请添加图片描述

请添加图片描述
小结
无比顺利,就是这样,满分10分给9.5分

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值