C++大一课设解析记录

首先,我们运用EA画出一个大概需求:

无标题.png

运用EA自动生成代码后,我们发现每种有.h 与.cpp两种文件

.h用来声明里面所包含的功能函数类,.cpp用来编写声明的函数或者类的编写

各个类的用途:

在main函数中,我们只需要编写最外层的交互界面,实现输入相关指令,就可以从Furniturecontainer中获取到要输出的结果(实现显示

在Furniturecontainer中,我们将他作为一个数据库,编写相应的动态内存代码,以及各种指令返回的字符串流(实现储蓄以及调用

在剩下的Furniture以及sofa、bookcase中,Furniture是一个主的类,sofa、bookcase为他的继承子类,在Furniture中我们完成两个子类共通的要储蓄的信息创建,在子类中完成各自特殊的信息创建(告知要储存的数据格式类型)

注:过于基础的知识这里不再提及(像是类的构造函数等知识),如果有疑问可以将相关名词带上C++去菜鸟教程、博客园、CSDN这几个网站上进行搜索

Furniture类

包含:规定需要传入的数值、类的析构、复制构造函数用于传入、转为字符串流的函数

//首先,定义声明的.h
#ifndef FURNITURE_H
#define FURNITURE_H
#include <string>
using namespace std;
class Furniture {
public:
    //沙发和书柜都包含名字价格库存,我们要先对他们进行声明(其中的变量要现在类当中声明)
	Furniture(string name = "?", double price = 0, int stock = -1);
	virtual ~Furniture();//析构函数,因为有两个继承类,所以我们用虚函数来实现多态
	Furniture(const Furniture& furniture);//复制构造函数
	void setName(string name);
	string getName() const;
	void setPrice(double price);//其他的set get 省略,格式都一样
	string toString() const;//将一样的数据转为字串流
	virtual string toStringSpec() const = 0;//将不一样的数据转为字串流
private:
	string name;
	double price;
	int stock;
};
#endif

= Furniture.cpp=//申明函数的实现
#include "Furniture.h"
#include <sstream>
using namespace std;
//将一开始申明的数据进行初始化
Furniture::Furniture(string name /* = "?" */, double price /* = 0 */, int stock /* = -1 */){
	this->name = name;
	this->price = price;
	this->stock = stock;
}
//析构函数
Furniture::~Furniture(){}
//此处将包含名字、库存、价格的Furniture变量通过引用的方式传入
Furniture::Furniture(const Furniture& furniture){
	this->name = furniture.name;
	this->price = furniture.price;
	this->stock = furniture.stock;
}
//仅仅展示name 的get set其他同理
void Furniture::setName(string name){
	this->name = name;
}
string Furniture::getName() const{
	return this->name;
}
string Furniture::toString() const{//将数据转为字串流方便之后的输出(convertor为自己取得名字)
	stringstream convertor;
	convertor << "The name is: " << this->name
		<< ", the price is: " << this->price
		<< ", and the stock is: " << this->stock
		<< toStringSpec();
	return convertor.str();
}

上段代码中涉及到的知识点:

析构函数:

用于函数的销毁,用' ~ '符号加函数名构成

虚函数:

虚函数可以有多种实现方法,运用虚函数我们可以实现多态:程序运行后才能知道要运行哪一个虚函数。比如定义上述虚构函数为虚函数,那么只有在实际执行的时候才知道程序要析构的是sofa还是bookcase

详细可参考此链接:https://www.cnblogs.com/Node-Sans-Blog/p/14249366.html

const:

表示变量的限定,放在函数的定义中意味着这个函数不能对任何数值进行改变,放在变量前面表示在这个函数中不能对这个变量经行改变

复制构造函数:

一般我们在程序中会用Furniture方法去定义一个变量A,其中A就包含A.name,A.price,A.stock.这里的复制构造函数运用(const Furniture& furniture)的方法直接通过传引用而不用复制就把整个A的数据传入函数当中,避免了内存泄漏

另:

&为取地址符号 this->表示这个变量是在这个类当中的变量 Furniture::(函数名)表示这个函数是从属于Furniture类当中的

SOFA类

包含:继承申明、sofa类的变量申明、析构、特殊变量转为字符串

#ifndef SOFA_H
#define SOFA_H
#include "Furniture.h"
#include <string>
using namespace std;
class Sofa :public Furniture {  //表示从Furniture中继承
public:
	Sofa(string name = "?", double price = 0, int stock = -1,int nrSeats = 0, string color = "?");
	virtual ~Sofa();
	Sofa(const Sofa& sofa);
    //只要申明Furniture类中没有的就好
	void setNrSeats(int nrSeats);
	int getNrSeats()const;
	void setColor(string color);
	string getColor() const;
	virtual string toStringSpec() const;//声明虚函数
private:
	int nrSeats;
	string color;
};
#endif

=sofa.cpp=
#include "Sofa.h"
#include <sstream>
using namespace std;
Sofa::Sofa(string name, double price, int stock,int nrSeats, string color) : Furniture(name,price,stock){
    //位于函数变量后,函数内容大括号前的表示声明继承
	this->nrSeats = nrSeats;
	this->color = color;
}
Sofa::~Sofa(){}
Sofa::Sofa(const Sofa& sofa) :Furniture(sofa){
	this->nrSeats = sofa.nrSeats;
	this->color = sofa.color;
}
//get set 函数省略
string Sofa::toStringSpec() const{//属于sofa的虚函数所要执行的内容
	stringstream convertor;
	convertor << ", Number of seats is: " << this->nrSeats
		<< ", and color is: " << this->color << endl;
	return convertor.str();
}

bookcase类同sofa 类的关系一致,这里遍不再做详细赘述了

Furniturecontainer类

创建容量池、析构函数、数据的传入(复制构造函数)、赋值号的重载、各种对于数据库内数据进行操作的函数

#ifndef FURNITURECONTAINER_H
#define FURNITURECONTAINER_H
#include "Furniture.h"
#include <string>
using namespace std;
enum FurnitureType {//表示有两个继承的函数
    SOFA, BOOKCASE
};
class FurnitureContainer {
public:
    FurnitureContainer(int capacity = 10);

    virtual ~FurnitureContainer();

    FurnitureContainer(const FurnitureContainer &originalObj);

    void operator=(const FurnitureContainer &originalObj);

    //省略了各种对数据进行操作的函数声明
private:
    Furniture **furnitureArray;
    int nrOfFurniture;
    int capacity;
    void expand();
};
#endif

FurnitureContainer 类是几个类中最难的一个,是动态分配的核心,下面我们来一起看看他的实现:

#include "FurnitureContainer.h"
#include "Bookcase.h"
#include "Sofa.h"
#include <sstream>
using namespace std;
//创建用于储蓄的数组(初始化)
FurnitureContainer::FurnitureContainer(int capacity){//传入数组容量
	this->capacity = capacity;
	this->nrOfFurniture = 0;//此时数组中已经有的数据数
	this->furnitureArray = new Furniture*[this->capacity];//创建Furniture类型的数组furnitureArray
	for (int i = 0; i < this->capacity; i++){//初始化数组
		this->furnitureArray[i] = nullptr;
	}
}
FurnitureContainer::~FurnitureContainer(){//析构函数时需要手动将数组中的数据以及数组本身进行删除
	for (int i = 0; i < this->nrOfFurniture; i++)	{
		delete this->furnitureArray[i];
	}
	delete[] this->furnitureArray;
}
FurnitureContainer::FurnitureContainer(const FurnitureContainer & originalObj){
	this->capacity = originalObj.capacity;
	this->nrOfFurniture = originalObj.nrOfFurniture;
	this->furnitureArray = new Furniture*[this->capacity];
    //准备好sofa类与bookcase类的指针变量(仅仅是申明,还没有创建,所以不用NEW)
	Sofa * sofaPtr = nullptr;
	Bookcase * bookcasePtr = nullptr;
	for (int i = 0; i < this->nrOfFurniture; i++)	{
		sofaPtr = dynamic_cast<Sofa*>(originalObj.furnitureArray[i]);//如果传入的数据不是sofa类他将返回空
		if (sofaPtr != nullptr){//如果是sofa类,创建sofa类对应的数据类型的数组
			this->furnitureArray[i] = new Sofa(*sofaPtr);
		}
        //bookcase类同理
		bookcasePtr = dynamic_cast<Bookcase*>(originalObj.furnitureArray[i]);
		if (bookcasePtr != nullptr){
			this->furnitureArray[i] = new Bookcase(*bookcasePtr);
		}
		for (int i = this->nrOfFurniture; i < this->capacity; i++){
			this->furnitureArray[i] = nullptr;
		}
	}
}
//赋值号的重载
void FurnitureContainer::operator=(const FurnitureContainer & originalObj){
	if (this != &originalObj){//this表示等于前的数
        //删除原本的数组
		for (int i = 0; i < this->nrOfFurniture; i++)	{
			delete this->furnitureArray[i];
		}
		delete[] this->furnitureArray;
        //创建新的数组
		this->capacity = originalObj.capacity;
		this->nrOfFurniture = originalObj.nrOfFurniture;
		this->furnitureArray = new Furniture*[this->capacity];
		//判断是sofa类还是bookcase类,并动态创建对应的数组
		Sofa * sofaPtr = nullptr;
		Bookcase * bookcasePtr = nullptr;
		for (int i = 0; i < this->nrOfFurniture; i++)	{
			sofaPtr = dynamic_cast<Sofa*>(originalObj.furnitureArray[i]);
			if (sofaPtr != nullptr){
				this->furnitureArray[i] = new Sofa(*sofaPtr);
			}
			bookcasePtr = dynamic_cast<Bookcase*>(originalObj.furnitureArray[i]);
			if (bookcasePtr != nullptr){
				this->furnitureArray[i] = new Bookcase(*bookcasePtr);
			}
			for (int i = this->nrOfFurniture; i < this->capacity; i++)	{
				this->furnitureArray[i] = nullptr;
			}
		}
	}
}
//————————————————————————————————————————————以下为功能实现(仅包含部分)————————————————————————————————————//
//主要为字符串输出流的运用
string FurnitureContainer::presentAll() const{
	stringstream convertor;
	convertor << "All the furniture: " << endl;
	for (int i = 0; i < this->nrOfFurniture; i++)	{
		convertor << this->furnitureArray[i]->toString();//*运用->去调用函数
	}
	convertor << endl;
	return convertor.str();
}
string FurnitureContainer::presentAllValuesByType(FurnitureType type) const{//显示sofa或者bookcase
	stringstream convertor;
	double valueSofa = 0;
	double valueBookcase = 0;
	for (int i = 0; i < this->nrOfFurniture; i++)	{
		if (dynamic_cast<Sofa*>(this->furnitureArray[i]) != nullptr){
			valueSofa += this->furnitureArray[i]->getPrice();
		}else {
			valueBookcase += this->furnitureArray[i]->getPrice();
		}
	}
	convertor << "the total value in stock of the is: "
		<< (type == SOFA ? valueSofa : valueBookcase) << endl;
	return convertor.str();
}
//添加数据函数
void FurnitureContainer::addSofa(string name, double price, int stock, int nrSeats, string color){
	if (this->nrOfFurniture == this->capacity){
		this->expand();
	}
	this->furnitureArray[this->nrOfFurniture++] = new Sofa(name, price, stock, nrSeats, color);
}
//删除数据
bool FurnitureContainer::remove(string name){
	int i = 0;
	bool isRemove = false;
	while (i < this->nrOfFurniture){
		if (this->furnitureArray[i]->getName() == name){
			delete this->furnitureArray[i];
			this->furnitureArray[i] = this->furnitureArray[--this->nrOfFurniture];//将最后的一个数据填充上楼来
			isRemove = true;
		}else{
			i++;
		}
	}
	return isRemove;
}
//扩大数组容量的数据
void FurnitureContainer::expand(){
	this->capacity += 10;
	Furniture** temp = new Furniture*[this->capacity];//双指针;指针数组
	for (int i = 0; i < this->nrOfFurniture; i++)	{//将原数据暂存于双指针temp中
		temp[i] = this->furnitureArray[i];
	}
	delete[] this->furnitureArray;//删除原来的
	this->furnitureArray = temp;//将temp放在新的地址当中
}
NEW

动态分配需要用new来创建数组来划定储蓄区域

详细可了解:https://blog.csdn.net/songthin/article/details/1703966

赋值号重载:

可参考链接:https://www.cnblogs.com/xiaoshiwang/p/9491365.html

t2 = t1;实际的运作方式是t2.operator=t1,所以函数里面的this就是t2

重载类FurnitureContainer的=号函数,当对类FurnitureContainer的对象用=号操作的时候,就会调用这个重载后的函数

指针

详情链接:https://www.runoob.com/cplusplus/cpp-pointers.html

指针是一个变量,其值为另一个变量的地址。

数组与指针:

int  var[MAX] = {10, 100, 200};
   int  *ptr;
   ptr = var;//var作为一个指向数组开头的常量,是不能修改的,但是可以用指针运算符,如:*(var+2)=500即var[2]=500
   for (int i = 0; i < MAX; i++)
   {
      cout << "var[" << i << "]的内存地址为 ";
      cout << ptr << endl;
      cout << "var[" << i << "] 的值为 ";
      cout << *ptr << endl;
      ptr++;// 移动到下一个位置
   }
双指针

QQ图片20210129210009.png

另:

①如果类中有函数,需要自己写复制构造函数实现深拷贝

②a[3]与*(a+3)效果相同(后者称为取间访)

③两个同类型指针相减表示中间间隔了多少

最后:

无标题.png

posted @ 2021-02-23 23:07  Solmidola  阅读(125)  评论(1)    收藏  举报