今天又来写博客啦!
昨天使用了面向过程的思维解决了隔定时长放炮问题。但今天又有了一些其他想法:
- 正是想到c++这个语言可以使用面向对象的编程,所以我才会想到,昨天的这个隔定时长放炮问题里面,可以如何应用OOP呢?
- 看了看,昨天的程序里面最多的是对数组的操作,其实可以把这些操作封装到类中。
- 同时也可以学习到多文件编程的好处。
- 也就算是复习了一遍OOP编程的知识点~
想看昨天的面向过程思维的,点击:萌新的c++积累01_几个人各隔一定时长放炮问题
题目如下
甲、乙、丙三人同时放鞭炮, 甲每隔 a 秒放一个, 乙每隔 b 秒放一个, 丙每隔 c 秒放一个, 他们各自都放 d 个。对给定的 a、b、c 和 d(a,b,c>0) (d是正整数) 求能听到多少声鞭炮响。 假设两个响声相差小于 0.001秒时,人无法区分。
本解决方法的思路
- 正是因为昨天那个程序里极多的操作都是操作数组,为了操作数组有着各式循环与条件判断,煞是复杂。所以,可以考虑把所有的操作都封装到一个类中,把各操作定义为类的成员函数。
- 既可以采用多文件的形式来定义类、定义类的成员函数、写主程序,
- 也可以采用单文件的形式,把所有的都写到一起。
首先,定义类
类的定义可以与主程序放在一个cpp文件中,也可以新建一个头文件(*.h)来存放类的定义。
代码如下:
#pragma once
//这个是为了避免一个文件被#include多次而使用的
class WVector
{
private:
int* stArray;//定义一个指针变量,存放数组的首地址
public:
int Count = 0;//这个变量用来计数,记录这个数组中数字的个数
public:
WVector();//默认构造函数
WVector(int size);//带数组大小的构造函数,具体定义后面会写
void SetSize(int size);//用c++老师的话来说,“setter”,用来申请一个动态数组
~WVector();//析构函数
bool Add(int item);//用来往数组里添加函数
void Update(int index, int item);//用来更新某一个位置上的数据
int Get(int index);//用来获得某一个位置上的数据
bool Contain(int item);//用来检测item是否已经存在于数组中
};
然后,定义类的成员函数
类的成员函数的定义,可以与主函数一起放在一个.cpp文件中,也可以新建一个.cpp文件专门用来定义,IDE会把不同文件里的这些定义串起来的。
代码如下(为了方便观看,把代码的解释以注释的形式放入):
#include "WVector.h"
// 这里如果类的定义是在.h头文件里声明的话
// 这个.cpp文件中必须先 #include"***.h"
WVector::WVector(int size)
{
SetSize(size);
//构造函数的原理与setter的原理是一样的,所以可以代码复用一下子
}
WVector::WVector()
{
stArray = nullptr;
//先把指针变量赋值成NULL,方便后续使用,也避免内存泄漏
}
void WVector::SetSize(int size)//设计setter
{
if (stArray != nullptr)
{
delete[] stArray;
stArray = nullptr;
}
stArray = new int[size];
for (int i = 0; i < size; i++)
stArray[i] = 0;
// 这里上面的那个if语句表示,如果stArray变量的值不是NULL的话,
// 就把之前的删除掉重新赋值,这样如果多次使用setter的话也可以避免内存泄漏。
// 千万注意!!!!!!!!
}
WVector::~WVector()
{
delete[] stArray;
stArray = nullptr;
// 析构函数清除掉申请的动态数组并且指针置为NULL自不必说!!!
}
bool WVector::Add(int item)
{
if (stArray != nullptr)
{
stArray[Count] = item;
Count++;//下标+1
return true;
}
return false;
// 这个函数用来往数组里添加元素,如果stArray这个指针变量为NULL的话
// 表示没有这个数组,这个时候返回false,即无法往指定的数组里填东西
// 如果stArray不是null的话,就可以往进填,返回true
}
int WVector::Get(int index)
{
if(index >= Count)//这里加入一个数组越界检查
return -1;//如果输入的索引值大于数组中元素的总数,返回-1
return stArray[index];
// getter的作用也自不必说
}
void WVector::Update(int index, int item)
{
if(index < Count)
stArray[index] = item;
// 这里要多加一句,如果index,即这个索引值比总数小的话,才可以往进填东西
// 如果大的话,数组越界访问是不可以的!所以这里加一步判断,
// 如果越界的话不做处理就可以了。
}
bool WVector::Contain(int item)
{
for (int j = 0; j < Count; j++)
{
if (stArray[j] == item)
{
return true;
}
}
return false;
//检查数组中是否含有某一个元素,逻辑简单,不必多说。
}
最后,写主程序
上面的所有铺垫已经具备了,下面就是要在主程序中使用刚刚定义好的类,以及在主程序中使用类的成员函数来达到自己的目的。
代码如下(依然使用注释解释):
#include "WVector.h"
如果是多文件程序的话这句话必须要有!不然之前写半天就是白费力气…
下面是正常的主函数的代码(为了方便观察,具体操作与昨天的具体代码稍有不同,在此不就题论题,仅谈方法):
int d;
WVector v1;//声明一个刚定义好的WVector的对象v1
cin >> d;
v1.SetSize(d);
int tmp = 0;//存放一个输入的待检查的数据
//如果是严格按照昨天的程序的话,下面的for循环中记录数据即可
for (int i = 0; i < d; i++)
{
cin >> tmp;//输入一个tmp,其实只要是对tmp赋值的操作都可以
if (v1.Contain(tmp) == false)//检查v1中是否包含
v1.Add(tmp);//不包含的话,加入
}
for (int i = 0; i < v1.Count; i++)//v1.Count就是v1中元素的个数
cout << v1.Get(i)<< " ";//输出v1中的每一个元素
这就是所有的代码!
出现的一些问题
这个代码中依然有问题,
具体可以看int WVector::Get(int index){……}这个函数部分
int WVector::Get(int index)
{
if(index >= Count)
return -1;
return stArray[index];
}
- 这里,如果输入的索引越界,返回-1.
- 但是,如果输入的某个索引,其对应的元素恰好也为-1呢?
- 也就是说,即使这里出现越界,返回了-1,用户一下子直观上无从知晓到底是这个地方的元素就是-1,还是因为越界,返回了代表出现越界的-1。
- 这里最好的一个方法就是,如果出现越界,能直接出现一个越界的提示,最好了。
- 之后再想想这个怎么改……
写在最后
这是第二次更博了,没想到用一个题目能做出这么多东西,哈哈!
明天也要继续加油鸭,也要继续更博,总结总结!让自己沉淀的更多!
加油!