《code complete(代码大全)》第18章表驱动法 代码

 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;
}

猜你喜欢

转载自blog.csdn.net/weixin_45339670/article/details/131620615
今日推荐