《面向对象程序设计》课程作业七
题目描述
请将随机生成数字、表达式的部分设计成:一个Random基类,基类中有random()方法。并由该基类派生出RandomNumber类、RandomOperation类,继承并覆盖父类方法。
学习简单工厂模式,思考能否将该模式运用到题目的第一点要求中。
普通的继承!
#include<iostream>
#include<ctime>
using namespace std;
class Random {
private:
static unsigned int seed;
public:
void Next();
virtual ~Random() {}
virtual void random() = 0;
};
unsigned int Random::seed = (unsigned int)time(NULL);
void Random::Next()/*每次随机后让种子变成一个新的*/
{
seed = seed * 11035 + 12345;
seed = (unsigned int)(seed / 65536) % 32768;
}
class RandomNum : public Random
{
private:
int num;
public:
RandomNum() { num = 0; }
virtual void random();
int GetNum() { return num; }
};
void RandomNum::random()
{
num = rand() % 11;
Next();
}
class RandomOper : public Random
{
private:
char oper;
public:
RandomOper() { oper = '+'; }
virtual void random();
char GetOper() { return oper; }
};
void RandomOper::random()
{
int choice = rand() % 4;
switch (choice)
{
case'0':oper = '+'; break;
case'1':oper = '-'; break;
case'2':oper = '*'; break;
case'3':oper = '/'; break;
default:
break;
}
Next();
}
int main()
{
RandomNum rnd1;
rnd1.random();
cout << rnd1.GetNum() << endl;
RandomOper rnd2;
rnd2.random();
cout << rnd2.GetOper() << endl;
return 0;
}
简单工厂:
工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。
工厂根据一个字符串来生成数字or运算符。
class RandomFactory
{
public:
Random createRandom(const string &s);
RandomFactory();
~RandomFactory();
};
Random * Randomfactory::creatrandom(const int & s)
{
if (s == "number")
{
return new RandomNum();
}
if (s == "operator")
{
return new RandomOper();
}
else
{
assert(false);
}
return NULL;
}
其余的部分逻辑相似,不贴了。
模板实现
我想到我学C#时,觉得C#自带的Random类特别方便。先创建一个Random类的对象比如rnd,然后就可以rnd.Next(int n) 生成一个随机数。
因为还要随机生成运算符,就用了模板。
一开始我还傻乎乎的以为很好写,就像下面这样:
这肯定是不行的,经过搜索,实现这样的功能要用到类模板特化的知识点。看看我的类声明:
template<class T>
class Random {
protected:
static unsigned int seed;
public:
static void NextSeed();
T Next();
};
如果你传int参数进去,Next方法就生成一个随机数,如果你传的是char,那么生成一个运算符。
但对于NextSeed方法,我们不希望将其特化,因为无论对于那种类型,NextSeed的行为都希望是一样的。这就涉及到类模板的成员函数的特化。写的时候报错无数,看文档也学到了不少,在代码中也注释了方便以后重看时回忆。
github上是简单继承和模板特化的两个写法。下图是实现了C#写法的效果:
学习链接:
编译器报错文档:
编译器错误 C2910检测到尝试两次显式专用化函数,C2248中不能访问访问成员声明,C2352非静态成员函数的非法调用