You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将类名作为变量实现派生类的延迟初始化?

问题描述

尝试遵循DRY原则封装父类/派生类的初始化逻辑时遇到两个问题:

  1. 无法动态指定要初始化的派生类(类名不能作为变量使用)
  2. 当前封装实现每次调用函数都会初始化新对象,无法做到仅在指针为空时才初始化

以下是相关代码示例:

类声明

#include <iostream>
class parent
{
private:
    int m_number;
public:
    parent() {}
    virtual void say_hello() { std::cout << "Hello. This is parent class!" << std::endl; }
    ~parent() {}
};

class derived1 : public parent
{
public:
    derived1(){}
    void say_hello() override { std::cout << "Hello. This is first derived class!" << std::endl; }
    ~derived1(){}
};
class derived2 : public parent
{
public:
    derived2() {}
    void say_hello() override { std::cout << "Hello. This is second derived class!" << std::endl; }
    ~derived2() {}
};

枚举状态

enum OutputMethod
{
    STATE_NONE,
    STATE_CLASS,
    STATE_EXIT
};

测试动作函数

#include <Windows.h>
#define VK_L_C 0x43
#define VK_L_N 0x4E
void action(OutputMethod &state)
{
    if (GetKeyState(VK_L_C) < 0)
    {
        state = STATE_CLASS;
    }
    else if (GetKeyState(VK_L_N) < 0)
    {
        state = STATE_NONE;
    }
    else if (GetKeyState(VK_ESCAPE) < 0)
    {
        state = STATE_EXIT;
    }
}

原始主函数逻辑

#include <iostream>
#include <string>
int main(void)
{
    derived1 *p_derived = nullptr;
    OutputMethod out_method;

    out_method = STATE_NONE;

    while (out_method != STATE_EXIT)
    {
        // Actions (C-class, N-none, ESC-endloop)
        action(out_method);

        //--------BEGINING of desired function----------
        if (out_method == STATE_NONE)
        {
            std::cout << "Hello from main!" << std::endl;
        }
        else if (out_method == STATE_CLASS)
        {
            if (p_derived == nullptr)
            {
                // 问题1:无法动态替换derived1为其他派生类
                p_derived = new derived1();
            }

            p_derived->say_hello();
        }

        if (out_method == STATE_NONE)
        {
            if (p_derived != nullptr)
            {
                delete p_derived;
                p_derived = nullptr;
            }
        }
        //-------------END of desired function----------
    }

    if (p_derived != nullptr)
    {
        delete p_derived;
        p_derived = nullptr;
    }

    std::string exit = "";
    std::getline(std::cin, exit);

    return 0;
}

尝试的封装函数(存在问题)

void output_state(parent *p_variable, parent* p_new, OutputMethod state_0, OutputMethod state_1, OutputMethod &state)
{
    if (state == state_0)
    {
        std::cout << "Hello from main!" << std::endl;
    }
    else if (state == state_1)
    {
        if (p_variable == nullptr)
        {
            // 问题2:p_new是提前创建的对象,每次调用函数都会新建,导致内存泄漏
            p_variable = p_new;
        }

        p_variable->say_hello();
    }

    if (state == state_0)
    {
        if (p_variable != nullptr)
        {
            delete p_variable;
            p_variable = nullptr;
        }
    }
}

调用方式(存在问题)

...
derived1 *p_derived = nullptr;
OutputMethod out_method;
out_method = STATE_NONE;

while (out_method != STATE_EXIT)
    {
        // Actions (C-class, N-none, ESC-endloop)
        action(out_method);
        // 每次调用都会执行new derived1(),即使指针不为空
        output_state(p_derived, new derived1(), STATE_NONE, STATE_CLASS, out_method);
    }
...

解决方案

通过传递对象创建逻辑(工厂回调)和传递指针的引用可以同时解决两个问题:

1. 修改封装函数,适配动态创建与指针更新

使用std::function传递派生类的创建逻辑,同时将指针参数改为引用类型,确保函数内的修改能同步到外部变量:

#include <functional>

void output_state(parent*& p_variable, const std::function<parent*()>& creator, 
                  OutputMethod state_0, OutputMethod state_1, OutputMethod& state)
{
    if (state == state_0)
    {
        std::cout << "Hello from main!" << std::endl;
        // 切换状态时销毁对象
        if (p_variable != nullptr)
        {
            delete p_variable;
            p_variable = nullptr;
        }
    }
    else if (state == state_1)
    {
        // 仅在指针为空时调用创建逻辑
        if (p_variable == nullptr)
        {
            p_variable = creator();
        }
        p_variable->say_hello();
    }
}

2. 主函数中调用封装函数

传递对应派生类的创建回调,即可动态切换要初始化的类:

#include <iostream>
#include <string>
#include <functional>

int main(void)
{
    parent* p_derived = nullptr; // 改为parent*适配多态
    OutputMethod out_method = STATE_NONE;

    while (out_method != STATE_EXIT)
    {
        action(out_method);
        
        // 传递derived1的创建逻辑,切换为derived2只需替换回调内容
        output_state(p_derived, [](){ return new derived1(); }, 
                     STATE_NONE, STATE_CLASS, out_method);
    }

    // 清理剩余对象
    if (p_derived != nullptr)
    {
        delete p_derived;
        p_derived = nullptr;
    }

    std::string exit = "";
    std::getline(std::cin, exit);

    return 0;
}

3. 额外优化:用智能指针避免手动内存管理

使用std::unique_ptr自动管理内存,无需手动调用delete,降低内存泄漏风险:

#include <memory>

void output_state(std::unique_ptr<parent>& p_variable, const std::function<parent*()>& creator,
                  OutputMethod state_0, OutputMethod state_1, OutputMethod& state)
{
    if (state == state_0)
    {
        std::cout << "Hello from main!" << std::endl;
        // 智能指针自动销毁对象
        p_variable.reset();
    }
    else if (state == state_1)
    {
        if (!p_variable)
        {
            p_variable.reset(creator());
        }
        p_variable->say_hello();
    }
}

// 主函数调用示例
int main(void)
{
    std::unique_ptr<parent> p_derived;
    OutputMethod out_method = STATE_NONE;

    while (out_method != STATE_EXIT)
    {
        action(out_method);
        output_state(p_derived, [](){ return new derived1(); }, 
                     STATE_NONE, STATE_CLASS, out_method);
    }

    std::string exit = "";
    std::getline(std::cin, exit);

    return 0;
}

关键改进点

  • 动态指定派生类:通过std::function传递创建逻辑,无需硬编码类名,切换派生类仅需修改回调内容。
  • 避免重复创建:仅在指针为空时执行创建逻辑,不会每次调用函数都新建对象。
  • 指针引用传递:确保函数内对指针的修改同步到外部变量,解决原封装中指针无法正确更新的问题。
  • 智能指针优化:自动管理内存,消除手动delete带来的内存泄漏风险。

内容的提问来源于stack exchange,提问作者skrovno_CZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 18:49:55