01问题描述:
02有关表驱动法的笔记:
最简单的例子:用户输入一个月份数,输出对应的天数。
这个问题最朴素的做法是
if(1月) 31天
if(2月) 28天
if(3月) 31天
if(4月) 30天
if(5月) 31天
if(6月) 30天
if(7月) 31天
if(8月) 31天
if(9月) 30天
if(10月) 31天
if(11月) 30天
if(12月) 31天
用一个一维数组代替很长的if,这就是表驱动法。
int M = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
cout << M[n-1];
关键点
1.映射(有时候输入内容并不是与下标一一对应)
2.表里存什么
03该问题的表驱动法解决方法伪代码
while (1)
{
读一个“浮标ID”
读表,可查询到该 *浮标ID* 后面跟的字段名称和数据类型
遍历该条记录的每个字段的格式信息
{
(读表,可查询到该 *浮标ID* 后面跟的字段名称和数据类型)
如果该项是int类型
读入int
打印字段名(在表里)
打印int
如果该项是string类型
读入string
打印字段名(在表里)
打印string
如果该项是double类型
读入double
打印字段名(在表里)
打印double
//... 可继续添加
}
}
可以借助多态,干掉上面的if
04完整代码:
# include <iostream>
# include <string>
// 标签种类数最大值
# define MAXMsgKinds 10
// 每条记录的字段数量最大值
# define MAXFIELDS 10
struct EveryField {
int dataTypeIndex;
std::string fieldTitle;
};
struct EveryRecord {
int numFields;
std::string recordTitle;
EveryField fields[MAXFIELDS];
};
class CBaseMsg { // Msg改为Field会更恰当
public:
virtual void inputData(void) = 0;
virtual void printData(void) = 0;
};
class CIntMsg : public CBaseMsg {
public:
int data;
void inputData(void) override { std::cin >> data; }
void printData(void) override { std::cout << data << std::endl; }
};
class CDoubleMsg : public CBaseMsg {
public:
double data;
void inputData(void) override { std::cin >> data; }
void printData(void) override { std::cout << data << std::endl; }
};
class CStringMsg : public CBaseMsg {
public:
std::string data;
void inputData(void) override { std::cin >> data; }
void printData(void) override { std::cout << data << std::endl; }
};
// 若要添加字段数据类型,如bool,则仅需写一个派生类,然后在程序第81行添加new CBoolMsg即可。
void init(EveryRecord * T)
{
T[0].numFields = 2;
T[0].recordTitle = "【个人资料】";
T[0].fields[0] = { 0, "【幸运数】" }; //int
T[0].fields[1] = { 2, "【姓名】" }; // string
T[1].numFields = 3;
T[1].recordTitle = "【期末成绩】";
T[1].fields[0] = { 1, "【数学】" }; //double
T[1].fields[1] = { 1, "【语文】" }; //double
T[1].fields[2] = { 1, "【外语】" }; //double
T[2].numFields = 5;
T[2].recordTitle = "【一天的体温变化】";
T[2].fields[0] = { 1, "【凌晨】" }; //double
T[2].fields[1] = { 1, "【清晨】" }; //double
T[2].fields[2] = { 1, "【正午】" }; //double
T[2].fields[3] = { 1, "【下午】" }; //double
T[2].fields[4] = { 1, "【傍晚】" }; //double
// 若要添加记录类型(原书中的“浮标ID”),则仅需继续写T[3]的内容即可,其余位置不变。
}
int main(void)
{
EveryRecord T[MAXMsgKinds];// 表驱动法:用一张表来描述每种消息的格式
init(T); //初始化表
// 3代表字段的数据类型的数量,本例中,目前添加了3中数据类型,分别是int double string
CBaseMsg * MsgTypeList[3] = { new CIntMsg , new CDoubleMsg , new CStringMsg };
int msgTag;
while (true)
{
std::cin >> msgTag;
std::cout << T[msgTag].recordTitle << std::endl;;
for (int i = 0; i < T[msgTag].numFields; ++i)
{
MsgTypeList[T[msgTag].fields[i].dataTypeIndex]->inputData();
std::cout << T[msgTag].fields[i].fieldTitle;
MsgTypeList[T[msgTag].fields[i].dataTypeIndex]->printData();
}
std::cout << std::endl;
}
return 0;
}