当前位置:C++技术网 > 资讯 > 练习项目:3 控制台项目(练习项目)基本框架完全实现和转换功能扩展(完结)

练习项目:3 控制台项目(练习项目)基本框架完全实现和转换功能扩展(完结)

更新时间:2015-06-25 22:49:00浏览次数:1+次

看本文前,请先阅读:

1. 《VS中控制台项目创建方法步骤

2. 《控制台项目(练习项目)基本框架实现

3. 《控制台项目(练习项目)基本框架扩展转换功能实现



 先看看程序运行截图:


      第一步扩展一个功能模块,这个和第3篇文章一样,就不细说了。我这里扩展的是Weight,实现重量【克、两、斤、公斤】之间的转换,因为本人经常在这几个单位里转换比较慢,所以就实现了这个,你可以实现其他的,程序的结构让你可以轻松的扩展,并且扩展格式可以参考项目中的代码,基本上是一样的,所以扩展性好,并且扩展起来也很快速。


下面就重量转换的看看代码,代码就不解释了,和长度的一样。

重量转换头文件代码:

/* - 设计开发编写:codexia ,分享自C++技术网 - */
/* 
  - 重量单位换算
  - 克、两、斤、公斤相互转换
*/
#define FROM_K  0 // - 源数据单位为克
#define FROM_L  1 // - 源数据单位为两
#define FROM_J  2 // - 源数据单位为斤
#define FROM_GJ 3 // - 源数据单位为公斤

void WeiControlRun();// - 重量转换控制器,不能在头文件中内联,否则会重定义
void WeiTip();

double WeiConvertToK (int iFlag,double uiSrc);// - 转换到克
double WeiConvertToL (int iFlag,double uiSrc);// - 转换到两
double WeiConvertToJ (int iFlag,double uiSrc);// - 转换到斤
double WeiConvertToGJ(int iFlag,double uiSrc);// - 转换到公斤

头文件新增函数说明:

1.WeiControlRun函数是重量转换控制函数,在这个函数中实现重量转换功能模块的持续运行,-1退出运行。

2.WeiTip函数则是简单的输出提示而已。


重量转换源文件代码(新增的,与第3篇文章长度转换相似的就不展示了,篇幅太长,最后给项目文件打包下载):

include "Weight.h"
#include "Afx.h"

void WeiControlRun()
{
    WeiTip();
    int iModuleCode =-2;
    double dTemp,dInput;
    while(iModuleCode!=-1)
    {
        AfxMessage("请输入重量转换模式:",false);
        iModuleCode = (int)AfxGetNum();
        switch(iModuleCode)
        {
        case 00:
            AfxMessage("请输入两:",false);
            dTemp = WeiConvertToK(FROM_L,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 两 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 克");
            break;
        case 01:
            AfxMessage("请输入斤:",false);
            dTemp = WeiConvertToK(FROM_J,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 斤 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 克");
            break;
        case 02:
            AfxMessage("请输入公斤:",false);
            dTemp = WeiConvertToK(FROM_GJ,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 公斤 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 克");
            break;
        case 10:
            AfxMessage("请输入克:",false);
            dTemp = WeiConvertToL(FROM_K,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 克 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 两");
            break;
        case 11:
            AfxMessage("请输入斤:",false);
            dTemp = WeiConvertToL(FROM_J,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 斤 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 两");
            break;
        case 12:
            AfxMessage("请输入公斤:",false);
            dTemp = WeiConvertToL(FROM_GJ,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 公斤 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 两");
            break;
        case 20:
            AfxMessage("请输入克:",false);
            dTemp = WeiConvertToJ(FROM_K,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 克 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 斤");
            break;
        case 21:
            AfxMessage("请输入两:",false);
            dTemp = WeiConvertToJ(FROM_L,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 两 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 斤");
            break;
        case 22:
            AfxMessage("请输入公斤:",false);
            dTemp = WeiConvertToJ(FROM_GJ,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 公斤 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 斤");
            break;
        case 30:
            AfxMessage("请输入克:",false);
            dTemp = WeiConvertToGJ(FROM_K,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 克 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 公斤");
            break;
        case 31:
            AfxMessage("请输入两:",false);
            dTemp = WeiConvertToGJ(FROM_L,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 两 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 公斤");
            break;
        case 32:
            AfxMessage("请输入斤:",false);
            dTemp = WeiConvertToGJ(FROM_J,dInput=AfxGetNum());
            AfxMessage(dInput,false);
            AfxMessage(" 斤 = ",false);
            AfxMessage(dTemp,false);
            AfxMessage(" 公斤");
            break;
        }
    }
}
void WeiTip()
{
    AfxMessage("------------重量转换模式说明------------");
    AfxMessage("00-两到克   01-斤到克   02-公斤到克\t");
    AfxMessage("10-克到两   11-斤到两   12-公斤到两\t");
    AfxMessage("20-克到斤   21-两到斤   22-公斤到斤\t");
    AfxMessage("30-克到公斤 31-两到公斤 32-斤到公斤\t");
    AfxMessage("-1退出\t");
    AfxMessage("----------------------------------------");
}

源文件代码说明:

1.上面两个函数代码上没什么复杂的,相信都很容易看懂。

2.使用的case中的数字,没有使用连续的,是为了让用户更容易选择。因为转换到一个单位的模式都属于同一个结果,所以分到一组编码中,如00,01,02.

3.每个case中代码几乎很相似,很容易检查错误。代码可能还可以精简,你可以试着精简。



下面是重量级的模块--程序主控制器模块,此模块控制程序的模块调用,和主程序的持续运行。持续运行和功能模块如成都转换、重量转换中的持续运行差不多,但是实现模块调用,并且可以实现很好的扩展性还是很费神的。下面给大家展示控制器的实现。对于函数指针不熟悉的,请阅读《函数名、函数类型、函数地址和函数指针》。对于Vector,就把vector当做一个动态数组即可,只是要在vector定义变量是要指定类型,因为它是使用模板实现的,使用方法在代码中很清楚了。

控制器头文件代码:

/* - 设计开发编写:codexia ,分享自C++技术网 - */
/* 
  - 提供各模块调用选择接口
*/
#ifndef AFX_CONVERT_CODEXIA // - 避免重复包含框架头文件
#define AFX_CONVERT_CODEXIA
#include "Afx.h"
#else
#endif

#define MODULE_LEN 0 // - 长度转换功能模块
#define MODULE_WEI 1 // - 重量转换功能模块

#include <vector>
using namespace std;
#include "Lenght.h"
#include "Weight.h"


/* - 模块列表二维数组 - */
/*
  - 数组元素由模块ID和功能模块控制器函数指针组成
  - 选择模块ID,启动对应的模块
  - 功能模块控制器函数格式:void (*p)(); 
*/
typedef  void (*PModuleCtl)();// - 定义模块启动函数指针类型
typedef struct
{
    int iModuleID;// - 模块的编号
    string strModuleName;// - 模块名
    PModuleCtl pModule; // - 模块启动函数指针,不能加星号,本身类型就是指针
}ModuleInfo;// - 模块信息结构体

static vector<ModuleInfo> g_ModuleList;// - 全局的模块列表


/* - 控制函数 - */

void CtlInitModuleList(vector<ModuleInfo> & ModuleList);// - 初始化模块列表

void CtlShowModuleList(); // - 显示支持的模块列表

int  CtlStartModule(int iModuleId);  // - 启动各个模块的功能控制器

void CtlAppRun();      // - 运行主程序控制器


代码说明:

1.CtlInitModuleList函数初始化列表,添加程序中支持的模块到全局模块列表中。在这里很好的扩展模块。

2.CtlShowModuleList函数显示已经初始化好的模块信息列表。

3.CtlStartModule启动参数中对应的模块,执行功能。

4.CtlAppRun这是启动控制器的入口函数,主函数main中,只要执行这个函数,就可以了。


控制器源文件代码:

#include "Control.h"

void CtlInitModuleList(vector<ModuleInfo> & ModuleList)
{
    /* - 初始化程序中支持的功能模块列表 - */
    ModuleInfo mi;
    mi.iModuleID = 0;
    mi.strModuleName="长度转换";
    mi.pModule = &LenControlRun;
    ModuleList.push_back(mi);

    mi.iModuleID = 1;
    mi.strModuleName="重量转换";
    mi.pModule = &WeiControlRun;
    ModuleList.push_back(mi);
}
void CtlShowList()
{
    /* - 显示程序中支持的功能模块列表 - */
    AfxMessage("-----------------------------------------------------------------");
    for (vector<ModuleInfo>::iterator it = g_ModuleList.begin();it!=g_ModuleList.end();it++)
    {
        AfxMessage("\t\t\t",false);
        AfxMessage(it->iModuleID,false);
        AfxMessage("\t",false);
        AfxMessage(it->strModuleName);
    }
    AfxMessage("\t\t\t",false);
    AfxMessage("-1\t退出程序");
    AfxMessage("-----------------------------------------------------------------");
}


int CtlStartModule(int iModuleId)
{
    /* - 启动模块控制器 - */
    int iRet = -2;
    switch(iModuleId)
    {
        case MODULE_LEN:
            g_ModuleList[iModuleId].pModule();// - 执行长度转换模块
            iRet = 0;
            break;
        case MODULE_WEI:
            g_ModuleList[iModuleId].pModule(); iRet = 1;// - 执行重量转换模块
            break;
        default:
            AfxMessage("您选择了退出,再见!");
            iRet = -2;
    }
    return iRet;
}

void CtlAppRun()
{
    /* - 运行程序主控制器 - */
    AfxMessage("-------------欢迎使用本程序,程序支持功能模块列表如下-------------");
    CtlInitModuleList(g_ModuleList);
    CtlShowList();
    AfxMessage("请选择操作:",false);
    int iModuleID = (int)AfxGetNum();
    int iRunModuleID = CtlStartModule(iModuleID);
    while(iModuleID!=-1)
    {
        //AfxMessage("【"+g_ModuleList[iRunModuleID].strModuleName+"】执行完毕!");
        CtlShowList();
        AfxMessage("请选择操作:",false);
        iModuleID = (int)AfxGetNum();
        if (iModuleID==-1)break;
        iRunModuleID = CtlStartModule(iModuleID);
    }
    AfxMessage("-------------感谢使用本程序,再见!-------------");

}


代码说明:

1.代码并不复杂,因为框架已经封装好了很多操作,只是调用函数即可。所以简化了编程,模块化后,逻辑很清晰。

2.vector是一个STL容器,添加一个元素使用push_back成员函数,传入数据即可,具体用法见代码。

3.在遍历vector容器时,建议不要用索引值来遍历,虽然可以将容器当做动态数组使用,也确实可以使用索引来遍历,但是毕竟不是真正的数组,只是使用起来可以当做数组来理解。所以,代码中使用迭代器的方式来遍历,迭代器就是it,在判断循环条件是不要使用大于小于的比较方式,使用!=来判断,这是和容器的特性有关,就不在这里展开讲解了。


框架中则扩展了输入的操作,便于输入。

框架头文件新增代码:

double AfxGetNum();// - 获取输入的数字

string AfxGetString();// - 获取输入的字符串

bool AfxGetChString(char * pcStr,int iCharCount);// - 获取char格式字符串


代码说明:


1.AfxGetNum获取输入,代替cin或者scanf,但是现在的版本没有格式化输入,以后可以扩展。返回值为double,兼容各种数字。

2.AfxGetString是string版本的字符串输入,AfxGetChString则是获取char版本的字符串,指针使用前必须有正确的指向,且在第二个参数中传入指向数组的字符大小。详细参看源代码。


框架源文件新增代码:

double AfxGetNum()
{
    double dTemp;
    cin>>dTemp;
    return dTemp;
}

string AfxGetString()
{
    string strTemp;
    cin>>strTemp;
    return strTemp;
}

bool AfxGetChString(char * pcStr,int iCharCount)
{
    bool bRet = false;
    if (pcStr==NULL)return false;
    for(int i=0;i<iCharCount;i++)
    {
        cin.get(pcStr[i]);
        if (pcStr[i]=='\n')i--;
    }
    pcStr[iCharCount]=0;
    return true;
}
框架新增源代码说明:


1.最后一个函数做了基本的检查,回车输入,会过滤换行符。

2.第一个函数输入数字需要增加检查,否则输入错误会带来问题,留作后续开发去完善了。


项目项目文件下载:点此下载