基于C++多态设计Vulkan API JSON多命令列表解析器
Vulkan命令解析器的面向对象设计方案
核心设计思路
用工厂模式+多态解决大量Vulkan命令的解析问题:定义抽象基类统一所有命令的接口,每个具体Vulkan命令对应一个派生类负责自身JSON解析逻辑;工厂类通过command_name字段映射创建对应派生类实例,彻底规避大量if/else分支。
1. 定义抽象命令基类
基类提供统一的解析、输出接口,存储所有命令的通用字段:
#include <nlohmann/json.hpp> #include <string> using json = nlohmann::json; class VulkanCommand { public: virtual ~VulkanCommand() = default; // 纯虚函数,由派生类实现具体解析逻辑 virtual void parse(const json& cmd_json) = 0; // 统一的命令信息输出接口 virtual void print() const = 0; const std::string& getCommandName() const { return command_name_; } protected: std::string command_name_; uint32_t call_index_; uint32_t thread_id_; std::string return_value_; };
2. 实现具体命令派生类
每个Vulkan命令对应一个派生类,专注解析自身特有参数结构:
示例:VkGetDeviceQueueCommand
class VkGetDeviceQueueCommand : public VulkanCommand { public: VkGetDeviceQueueCommand() { command_name_ = "vkGetDeviceQueue"; } void parse(const json& cmd_json) override { // 解析通用字段 call_index_ = cmd_json["call_index"]; thread_id_ = cmd_json["threadId"]; return_value_ = cmd_json["return_value"]; // 解析特有参数 const auto& params = cmd_json["parameters"]; device_ = params["device"]; queue_family_index_ = params["queueFamilyIndex"]; queue_index_ = params["queueIndex"]; p_queue_ = params["pQueue"]; } void print() const override { std::cout << "Command: " << command_name_ << "\n" << "Call Index: " << call_index_ << "\n" << "Thread ID: " << thread_id_ << "\n" << "Return Value: " << return_value_ << "\n" << "Parameters:\n" << " Device: " << device_ << "\n" << " Queue Family Index: " << queue_family_index_ << "\n" << " Queue Index: " << queue_index_ << "\n" << " pQueue: " << p_queue_ << "\n\n"; } private: std::string device_; uint32_t queue_family_index_; uint32_t queue_index_; std::string p_queue_; };
示例:VkCreateFenceCommand
// 嵌套参数对应的辅助结构体 struct FenceCreateInfo { std::string s_type; std::string flags; std::string p_next; }; class VkCreateFenceCommand : public VulkanCommand { public: VkCreateFenceCommand() { command_name_ = "vkCreateFence"; } void parse(const json& cmd_json) override { // 解析通用字段 call_index_ = cmd_json["call_index"]; thread_id_ = cmd_json["threadId"]; return_value_ = cmd_json["return_value"]; // 解析特有参数 const auto& params = cmd_json["parameters"]; device_ = params["device"]; // 解析嵌套的pCreateInfo const auto& create_info_json = params["pCreateInfo"]; create_info_.s_type = create_info_json["sType"]; create_info_.flags = create_info_json["flags"]; create_info_.p_next = create_info_json["pNext"]; p_allocator_ = params["pAllocator"]; p_fence_ = params["pFence"]; } void print() const override { std::cout << "Command: " << command_name_ << "\n" << "Call Index: " << call_index_ << "\n" << "Thread ID: " << thread_id_ << "\n" << "Return Value: " << return_value_ << "\n" << "Parameters:\n" << " Device: " << device_ << "\n" << " Fence Create Info:\n" << " sType: " << create_info_.s_type << "\n" << " flags: " << create_info_.flags << "\n" << " pNext: " << create_info_.p_next << "\n" << " pAllocator: " << p_allocator_ << "\n" << " pFence: " << p_fence_ << "\n\n"; } private: std::string device_; FenceCreateInfo create_info_; std::string p_allocator_; std::string p_fence_; };
3. 实现命令工厂类
工厂类通过哈希表存储命令名称到实例创建函数的映射,新增命令只需注册,无需修改工厂逻辑:
#include <unordered_map> #include <functional> #include <memory> class VulkanCommandFactory { public: // 单例模式,保证全局唯一工厂实例 static VulkanCommandFactory& getInstance() { static VulkanCommandFactory instance; return instance; } // 注册命令:绑定命令名称与实例创建函数 void registerCommand(const std::string& cmd_name, std::function<std::unique_ptr<VulkanCommand>()> creator) { creators_[cmd_name] = std::move(creator); } // 根据JSON创建对应命令实例并完成解析 std::unique_ptr<VulkanCommand> createCommand(const json& cmd_json) { std::string cmd_name = cmd_json["command_name"]; auto it = creators_.find(cmd_name); if (it != creators_.end()) { auto cmd = it->second(); cmd->parse(cmd_json); return cmd; } // 处理未知命令,返回空指针 return nullptr; } private: VulkanCommandFactory() = default; ~VulkanCommandFactory() = default; VulkanCommandFactory(const VulkanCommandFactory&) = delete; VulkanCommandFactory& operator=(const VulkanCommandFactory&) = delete; std::unordered_map<std::string, std::function<std::unique_ptr<VulkanCommand>()>> creators_; };
4. 注册命令并运行解析逻辑
初始化时注册所有支持的命令,然后逐行读取并解析JSON文件:
#include <iostream> #include <fstream> #include <string> // 简化注册逻辑的宏 #define REGISTER_VK_COMMAND(cmd_class) \ VulkanCommandFactory::getInstance().registerCommand(#cmd_class, []() { return std::make_unique<cmd_class>(); }) int main() { // 注册所有支持的Vulkan命令 REGISTER_VK_COMMAND(VkGetDeviceQueueCommand); REGISTER_VK_COMMAND(VkCreateFenceCommand); // 读取多行JSON文件 std::ifstream file("vulkan_commands.json"); if (!file.is_open()) { std::cerr << "Failed to open command file\n"; return 1; } std::string line; while (std::getline(file, line)) { if (line.empty()) continue; try { json cmd_json = json::parse(line); auto cmd = VulkanCommandFactory::getInstance().createCommand(cmd_json); if (cmd) { cmd->print(); } else { std::cout << "Unknown command: " << cmd_json["command_name"] << "\n"; } } catch (const json::parse_error& e) { std::cerr << "Parse error: " << e.what() << "\n"; } } return 0; }
扩展说明
- 新增命令:只需创建对应派生类,调用
REGISTER_VK_COMMAND宏注册即可,完全符合开放封闭原则。 - 嵌套参数:可通过定义辅助结构体/类处理,保持解析逻辑的清晰性。
- 错误处理:可在基类或工厂中添加参数校验、异常捕获逻辑,提升鲁棒性。
内容的提问来源于stack exchange,提问作者Andre Ahmed
相关产品推荐
相关产品推荐

