qq_41945416 2025-11-05 23:44 采纳率: 90.6%
浏览 7
已结题

关于mfc的重写、继承和串行化并行化问题

1.1为什么要继承类和重写其中的函数呢?为什么我们很少看到以CDialogEx dlg;dlg.DoModal();的形式来打开对话框呢?为什么永远是先用CDemoDlg继承于CDialogEx,然后再调用CDemoDlg的DoModal();才打开对话框呢?难道仅仅只是做更类名处理,或者只是声明该类的其他别名这么简单吗?
我觉得应该不会这么简单,我认为继承,重写,乃至重载都是为了让程序员更进一步的控制类的行为和加入自定义类的行为,以实现更好的编程效果,事实上真的是这样吗?
1.2 使用mfc+ado+sqlserver 开发的某信息管理系统,在登录界面会有很多信息需要使用者填写,比如,数据库服务器IP 端口号 用户名 密码 ,以及信息管理系统的用户名和密码 等等,需要填写的东西非常多,如果每次打开都是空白的需要使用者逐项填写,会浪费时间,造成使用不良感知。可以使用注册表保存这些数据,也可以使用串行化并行化保存读取这些数据。
串行化保存的这个文件,我们暂且称为“证书”
这些全用CString 做了控件变量和数据交换保存起来了,思路很重要,有个问题要明确啊,串行化证书的时候是串行化这些CString对象,还是串行化登录对话框的这个类?不管是CString还是CDialogEx,这些类已经基于CObject了,那还额外需要添加支持串行化的宏吗?
完整的通过登录对话框,假如串行化、并行化分别一个按钮 那串行化证书,和并行化证书的代码应该是怎样的?

  • 写回答

4条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-11-05 23:55
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .
    每日一句正能量,让它带给您好心情:做一个积极向上的人,读温柔的句子,见阳光的人,眼里全是温柔和笑意。
    .

    1.1 关于继承和重写的问题

    在 MFC 中,继承和重写是面向对象编程的核心机制,它们不仅仅是简单的类名替换或别名声明。以下是详细解释:

    1. 继承的目的
    • 扩展功能:通过继承基类(如 CDialogEx),可以在派生类(如 CDemoDlg)中添加新的成员变量、方法或自定义行为。例如,你可能需要在对话框中添加数据验证、自定义事件处理或界面逻辑。
    • 重写函数:基类中的虚函数(如 OnInitDialogOnOK)允许派生类重写默认行为。例如,你可以重写 OnInitDialog 来初始化控件,或重写 OnOK 来验证输入数据。
    • 代码复用和维护:继承使得公共逻辑集中在基类中,派生类只需关注特定功能,减少代码冗余。
    1. **为什么不用 CDialogEx dlg; dlg.DoModal();**:
    • 直接使用 CDialogEx 实例无法自定义对话框行为。通过派生类,你可以:
    • 添加控件变量(如 CString m_strUsername)。
    • 重写事件处理(如按钮点击、数据交换)。
    • 实现对话框资源与类的绑定(通过 DDX_ControlDDX_Text)。
    1. 重写与重载的作用
    • 你的理解是正确的:继承、重写和重载都是为了增强对类的控制,实现更灵活的编程。例如,通过重写 OnPaint,可以自定义绘制界面;通过重载构造函数,可以初始化特定数据。

    示例代码

    // 自定义对话框类
    class CDemoDlg : public CDialogEx
    {
    public:
        CDemoDlg(CWnd* pParent = nullptr) : CDialogEx(IDD_DEMO_DIALOG, pParent) {}
        
        // 重写初始化函数
        virtual BOOL OnInitDialog() override
        {
            CDialogEx::OnInitDialog();
            // 自定义初始化代码
            return TRUE;
        }
        
        // 重写OK按钮事件
        virtual void OnOK() override
        {
            // 数据验证逻辑
            CDialogEx::OnOK();
        }
        
        // 成员变量
        CString m_strData;
    };
    
    
    // 使用方式
    CDemoDlg dlg;
    dlg.DoModal();
    

    1.2 串行化与并行化保存登录数据

    思路分析

    • 数据保存方式:可以选择串行化单个 CString 对象,或串行化整个对话框类。后者更符合面向对象设计,因为对话框类封装了所有登录数据。
    • 串行化基础:MFC 的串行化机制依赖于 CObject 派生类。CStringCDialogEx 已间接继承自 CObject,但需在自定义类中显式添加串行化支持。

    实现步骤

    1. 在对话框类中添加串行化支持
    • 使用 DECLARE_SERIALIMPLEMENT_SERIAL 宏。
    • 重写 Serialize 函数。
    1. 串行化与并行化按钮代码
    • 串行化(保存数据到文件)。
    • 并行化(从文件加载数据)。

    示例代码

    对话框类定义(头文件):
    class CLoginDlg : public CDialogEx
    {
        DECLARE_SERIAL(CLoginDlg) // 声明串行化
    
    
    public:
        CLoginDlg(CWnd* pParent = nullptr);
        virtual void Serialize(CArchive& ar) override; // 重写串行化函数
    
    
        // 控件变量
        CString m_strDbIP;
        CString m_strDbPort;
        CString m_strDbUser;
        CString m_strDbPassword;
        CString m_strAppUser;
        CString m_strAppPassword;
    
    
        // 按钮事件处理
        afx_msg void OnBnClickedSerialize();
        afx_msg void OnBnClickedDeserialize();
    };
    
    对话框类实现(源文件):
    IMPLEMENT_SERIAL(CLoginDlg, CDialogEx, 1) // 实现串行化(版本号=1)
    
    
    CLoginDlg::CLoginDlg(CWnd* pParent) : CDialogEx(IDD_LOGIN_DIALOG, pParent) {}
    
    
    void CLoginDlg::Serialize(CArchive& ar)
    {
        if (ar.IsStoring())
        {
            // 串行化:保存数据到文件
            ar << m_strDbIP << m_strDbPort << m_strDbUser 
               << m_strDbPassword << m_strAppUser << m_strAppPassword;
        }
        else
        {
            // 并行化:从文件加载数据
            ar >> m_strDbIP >> m_strDbPort >> m_strDbUser 
               >> m_strDbPassword >> m_strAppUser >> m_strAppPassword;
        }
    }
    
    
    // 串行化按钮事件(保存数据)
    void CLoginDlg::OnBnClickedSerialize()
    {
        UpdateData(TRUE); // 将控件数据更新到变量
        CFile file("login.dat", CFile::modeCreate | CFile::modeWrite);
        CArchive ar(&file, CArchive::store);
        Serialize(ar);
        ar.Close();
        file.Close();
    }
    
    
    // 并行化按钮事件(加载数据)
    void CLoginDlg::OnBnClickedDeserialize()
    {
        CFile file("login.dat", CFile::modeRead);
        CArchive ar(&file, CArchive::load);
        Serialize(ar);
        ar.Close();
        file.Close();
        UpdateData(FALSE); // 将变量数据更新到控件
    }
    

    注意事项

    • 文件路径:示例中使用相对路径 "login.dat",实际项目中可指定绝对路径。
    • 错误处理:需添加文件打开失败的异常处理(如 CFileException)。
    • 数据加密:敏感数据(如密码)建议加密后存储。

    通过上述方式,登录数据会被保存到文件,下次启动时自动加载,提升用户体验。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 11月14日
  • 已采纳回答 11月6日
  • 创建了问题 11月5日