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

如何创建宏避免重复定义基础相同的Class?以RegisterScript为例

Absolutely! Macros are a perfect fit for cutting down on repetitive class code—especially when you’re dealing with script registration workflows where every class follows the exact same structure. Let’s walk through how to build this, using a typical RegisterScript scenario as an example.

Basic Macro for Script-Bound Classes

Let’s assume every class you need to define has:

  • A default constructor/destructor
  • A static RegisterScript() method that binds the class and its methods to your script engine
  • A set of common methods with identical signatures (and possibly default implementations)

Here’s a macro that generates this structure automatically, just by passing the class name:

#define DEFINE_SCRIPT_BOUND_CLASS(CLASS_NAME) \
class CLASS_NAME { \
public: \
    CLASS_NAME() = default; \
    ~CLASS_NAME() = default; \
    \
    static void RegisterScript() { \
        // Replace this with your actual script registration logic \
        ScriptEngine::RegisterClass<CLASS_NAME>(); \
        ScriptEngine:: RegisterMethod<CLASS_NAME, &CLASS_NAME::OnUpdate>("OnUpdate"); \
        ScriptEngine:: RegisterMethod<CLASS_NAME, &CLASS_NAME::GetName>("GetName"); \
    } \
    \
    void OnUpdate(float deltaTime) { \
        // Default implementation (can be overridden if needed) \
    } \
    \
    std::string GetName() const { \
        return #CLASS_NAME; // Uses stringification to return the class name \
    } \
};

How to Use It

Generating a new class is as simple as calling the macro with your desired class name:

DEFINE_SCRIPT_BOUND_CLASS(PlayerCharacter)
DEFINE_SCRIPT_BOUND_CLASS(EnemyAI)
DEFINE_SCRIPT_BOUND_CLASS(InteractiveObject)

Each of these will expand into a full class with all the boilerplate you need, no repeated code required.

Handling Customizable Logic

If some classes need to override default methods or add extra members, you can adjust the macro to support virtual functions:

#define DEFINE_SCRIPT_BOUND_CLASS(CLASS_NAME) \
class CLASS_NAME { \
public: \
    CLASS_NAME() = default; \
    virtual ~CLASS_NAME() = default; \
    \
    static void RegisterScript() { \
        ScriptEngine::RegisterClass<CLASS_NAME>(); \
        ScriptEngine:: RegisterMethod<CLASS_NAME, &CLASS_NAME::OnUpdate>("OnUpdate"); \
        ScriptEngine:: RegisterMethod<CLASS_NAME, &CLASS_NAME::GetName>("GetName"); \
    } \
    \
    virtual void OnUpdate(float deltaTime) { \
        // Default implementation \
    } \
    \
    virtual std::string GetName() const { \
        return #CLASS_NAME; \
    } \
};

Then you can extend the class normally if you need custom behavior:

class PlayerCharacter : public PlayerCharacterBase {
public:
    void OnUpdate(float deltaTime) override {
        // Custom player update logic
        PlayerCharacterBase::OnUpdate(deltaTime); // Call default if needed
    }
};
Alternatives to Macros (If You Prefer)

If macros feel too "hacky" for your taste, you can use the Curiously Recurring Template Pattern (CRTP) to achieve similar results without preprocessor magic:

template<typename Derived>
class ScriptBoundBase {
public:
    static void RegisterScript() {
        ScriptEngine::RegisterClass<Derived>();
        ScriptEngine:: RegisterMethod<Derived, &Derived::OnUpdate>("OnUpdate");
        ScriptEngine:: RegisterMethod<Derived, &Derived::GetName>("GetName");
    }

    virtual void OnUpdate(float deltaTime) = default;
    virtual std::string GetName() const {
        return typeid(Derived).name(); // Less clean than macro stringification, but works
    }
};

// Usage
class PlayerCharacter : public ScriptBoundBase<PlayerCharacter> {
    // Override methods as needed
};

That said, macros are often more straightforward for this exact use case—they let you generate full class definitions with unique names without needing to inherit from a base template.

Key Notes
  • Always wrap your macro in #undef if you’re redefining it later to avoid conflicts: #undef DEFINE_SCRIPT_BOUND_CLASS
  • When debugging, remember that macros expand inline—you can check your compiler’s preprocessed output to verify the generated code
  • Keep the macro focused on the repetitive boilerplate; leave custom logic to class extensions or overrides

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:30:39