当前位置: 首页 > news >正文

模拟C++简易配置系统(模板类 + 全局管理)

完整代码

#include <string>
#include <map>
#include <memory>
#include <stdexcept>
#include<iostream>// 1. 配置基类(统一接口)
class ConfigVarBase {
public:using ptr = std::shared_ptr<ConfigVarBase>;  // 智能指针别名ConfigVarBase(const std::string& name, const std::string& desc = ""): m_name(name), m_desc(desc) {}const std::string& getName() const { return m_name; }const std::string& getDesc() const { return m_desc; }// 纯虚函数:值转字符串 / 字符串转值(子类实现)virtual std::string toString() = 0;virtual bool fromString(const std::string& val) = 0;protected:std::string m_name;  // 配置名称(如"server.port")std::string m_desc;  // 配置描述
};// 2. 具体类型配置类(模板类,继承基类)
template<class T>
class ConfigVar : public ConfigVarBase {
public:using ptr = std::shared_ptr<ConfigVar<T>>;  // 智能指针别名ConfigVar(const std::string& name, const T& default_val, const std::string& desc = ""): ConfigVarBase(name, desc), m_val(default_val) {}// 实现基类接口:值转字符串(简化版)std::string toString() override {return std::to_string(m_val);  // 仅支持int等基础类型}// 实现基类接口:字符串转值(简化版)bool fromString(const std::string& val) override {try {m_val = std::stoi(val);  // 仅支持int类型转换(示例)return true;}catch (...) {return false;}}// 获取/设置值(核心功能)T getValue() const { return m_val; }void setValue(const T& v) { m_val = v; }private:T m_val;  // 存储具体类型的值(由模板参数T决定)
};// 3. 配置管理器(全局管理所有配置)
class Config {
public:// 存储所有配置的map(键:名称,值:基类指针)using ConfigMap = std::map<std::string, ConfigVarBase::ptr>;// 模板函数:查找或创建配置template<class T>static typename ConfigVar<T>::ptr Lookup(const std::string& name,const T& default_val,const std::string& desc = "") {// 先查是否已存在auto it = s_datas.find(name);if (it != s_datas.end()) {// 转换为具体类型并返回return std::dynamic_pointer_cast<ConfigVar<T>>(it->second);}// 检查名称合法性(简化版)if (name.find("!") != std::string::npos) {  // 禁止特殊字符throw std::invalid_argument("无效配置名称: " + name);}// 创建新配置并加入全局mapauto new_var = std::make_shared<ConfigVar<T>>(name, default_val, desc);s_datas[name] = new_var;return new_var;}// 模板函数:仅查找配置template<class T>static typename ConfigVar<T>::ptr Lookup(const std::string& name) {auto it = s_datas.find(name);if (it != s_datas.end()) {return std::dynamic_pointer_cast<ConfigVar<T>>(it->second);}return nullptr;  // 没找到返回空}private:static ConfigMap s_datas;  // 全局配置存储(静态成员)
};// 初始化全局配置map
Config::ConfigMap Config::s_datas;
int main() {// 1. 创建/获取int类型配置(端口,默认8080)auto port = Config::Lookup<int>("server.port", 8080, "服务器端口");// 2. 使用配置std::cout << "当前端口: " << port->getValue() << std::endl;  // 输出8080// 3. 修改配置port->setValue(443);std::cout << "修改后的端口: " << port->getValue() << std::endl;  // 输出443// 4. 再次获取配置(全局生效)auto same_port = Config::Lookup<int>("server.port");std::cout << "再次获取端口: " << same_port->getValue() << std::endl;  // 输出443
}

一、整体架构

代码通过三个核心组件实现通用配置管理:

  • ConfigVarBase:所有配置的基类(统一接口)
  • ConfigVar<T>:模板类,存储具体类型的配置值
  • Config:配置管理器,全局管理所有配置

二、逐类解析

1. 基类 ConfigVarBase

作用:提供统一接口,让不同类型的配置能被全局存储和管理。

class ConfigVarBase {
public:using ptr = std::shared_ptr<ConfigVarBase>;  // 智能指针别名(简化写法)// 构造函数:初始化名称和描述ConfigVarBase(const std::string& name, const std::string& desc = ""): m_name(name), m_desc(desc) {}// 获取配置名称和描述(所有配置通用)const std::string& getName() const { return m_name; }const std::string& getDesc() const { return m_desc; }// 纯虚函数:强制子类实现值与字符串的互转virtual std::string toString() = 0;                  // 值 → 字符串virtual bool fromString(const std::string& val) = 0;  // 字符串 → 值protected:std::string m_name;  // 配置名称(如"server.port")std::string m_desc;  // 配置描述(如"服务器端口")
};

关键点

  • 纯虚函数 toString() 和 fromString() 是核心接口,确保所有配置都能转为字符串(方便存储)和从字符串恢复。

  • 智能指针别名 ptr 统一管理所有配置对象的生命周期。

2. 模板类 ConfigVar<T>

作用:存储具体类型的配置值(如 int/string),实现类型安全的读写。

template<class T>
class ConfigVar : public ConfigVarBase {
public:using ptr = std::shared_ptr<ConfigVar<T>>;  // 具体类型的智能指针// 构造函数:初始化名称、默认值、描述(调用基类构造)ConfigVar(const std::string& name, const T& default_val, const std::string& desc = ""): ConfigVarBase(name, desc), m_val(default_val) {}// 实现基类接口:T类型值 → 字符串std::string toString() override {return std::to_string(m_val);  // 示例:int转字符串}// 实现基类接口:字符串 → T类型值bool fromString(const std::string& val) override {try {m_val = std::stoi(val);  // 示例:字符串转intreturn true;} catch (...) {return false;  // 转换失败返回false}}// 类型安全的读写接口(核心功能)T getValue() const { return m_val; }    // 获取值(返回T类型)void setValue(const T& v) { m_val = v; }  // 设置值(只能传T类型)private:T m_val;  // 存储具体类型的值(由模板参数T决定)
};

关键点

  • 模板参数 T:决定配置值的类型(如 int),让一份代码支持多种类型。
  • 类型安全getValue() 和 setValue() 只能操作 T 类型,编译器会检查类型错误(如给 int 类型传字符串会报错)。
  • 接口实现toString() 和 fromString() 完成值与字符串的转换(示例仅支持 int,可扩展到 string 等类型)。

3. 配置管理器 Config

作用:全局管理所有配置,负责创建、查找和维护配置的唯一性。

class Config {
public:// 配置存储容器:键(名称)→ 值(基类指针)using ConfigMap = std::map<std::string, ConfigVarBase::ptr>;// 模板函数1:查找或创建配置(带默认值)template<class T>static typename ConfigVar<T>::ptr Lookup(const std::string& name,const T& default_val, const std::string& desc = "") {// 步骤1:检查配置是否已存在auto it = s_datas.find(name);if (it != s_datas.end()) {// 存在则转换为具体类型并返回(确保类型匹配)return std::dynamic_pointer_cast<ConfigVar<T>>(it->second);}// 步骤2:检查名称合法性(简化版:禁止"!")if (name.find("!") != std::string::npos) {throw std::invalid_argument("无效配置名称: " + name);}// 步骤3:创建新配置并加入全局存储auto new_var = std::make_shared<ConfigVar<T>>(name, default_val, desc);s_datas[name] = new_var;  // 存入mapreturn new_var;}// 模板函数2:仅查找配置(不带默认值)template<class T>static typename ConfigVar<T>::ptr Lookup(const std::string& name) {auto it = s_datas.find(name);if (it != s_datas.end()) {return std::dynamic_pointer_cast<ConfigVar<T>>(it->second);}return nullptr;  // 没找到返回空}private:static ConfigMap s_datas;  // 全局配置存储(静态成员,全程序唯一)
};// 初始化全局配置容器
Config::ConfigMap Config::s_datas;

关键点

  • 全局存储 s_datas:静态 map 容器,存储所有配置(键为名称,确保唯一)。
  • Lookup 函数
  • 带默认值版本:首次调用创建配置并存入 s_datas,后续调用直接返回已存在的配置。
  • 仅查找版本:只查询不创建,找不到返回 nullptr。 

类型转换std::dynamic_pointer_cast 将基类指针转为具体类型指针(如 ConfigVar<int>),确保操作的是正确类型的配置(下行转换)。

下行转换关键点整理

继承关系:

ConfigVar<T>(派生类)继承自 ConfigVarBase(基类)。

存储时的上行转换:

// 存入时:派生类指针自动转为基类指针(上行转换,隐式)
s_datas["port"] = std::make_shared<ConfigVar<int>>("port", 8080);

s_datas 存储的是 基类指针ConfigVarBase::ptr),丢失了具体类型信息。

使用时的下行转换:

// 取出时:必须从基类指针转回派生类指针(下行转换,显式)
return std::dynamic_pointer_cast<ConfigVar<T>>(it->second);

基类 ConfigVarBase 没有 getValue() 等方法,必须转换为 ConfigVar<T> 才能使用具体类型的功能。

auto new_var = std::make_shared<ConfigVar<T>>(name, default_val, desc);的作用

  • 创建对象:在堆上构造 ConfigVar<T> 对象。
  • 包装指针:返回 std::shared_ptr 自动管理对象生命周期。
  • 优化内存:单次分配内存,比手动 new 更高效安全。

4. 主函数示例(使用流程)

int main() {// 1. 创建/获取int类型配置(端口,默认8080)auto port = Config::Lookup<int>("server.port", 8080, "服务器端口");// 2. 使用配置std::cout << "当前端口: " << port->getValue() << std::endl;  // 输出8080// 3. 修改配置port->setValue(443);std::cout << "修改后端口: " << port->getValue() << std::endl;  // 输出443// 4. 再次获取同一配置(全局生效)auto same_port = Config::Lookup<int>("server.port");std::cout << "再次获取端口: " << same_port->getValue() << std::endl;  // 输出443return 0;
}

流程解析

  • 首次调用 Lookup<int>("server.port", 8080):创建 ConfigVar<int> 对象,存入 s_datas

  • 修改值后,所有获取该配置的地方都会拿到新值(全局唯一)。


文章转载自:
http://balsas.riewr.cn
http://challah.riewr.cn
http://abruption.riewr.cn
http://acapulco.riewr.cn
http://burglarious.riewr.cn
http://chowder.riewr.cn
http://baguio.riewr.cn
http://analgetic.riewr.cn
http://bonn.riewr.cn
http://ashore.riewr.cn
http://berat.riewr.cn
http://bowsprit.riewr.cn
http://budworm.riewr.cn
http://cheilitis.riewr.cn
http://cardigan.riewr.cn
http://airiness.riewr.cn
http://catacombs.riewr.cn
http://bloom.riewr.cn
http://alcaide.riewr.cn
http://automania.riewr.cn
http://cambridgeshire.riewr.cn
http://bromid.riewr.cn
http://calfhood.riewr.cn
http://brocoli.riewr.cn
http://adieu.riewr.cn
http://bauson.riewr.cn
http://aphemic.riewr.cn
http://anthroposophy.riewr.cn
http://agapemone.riewr.cn
http://aspherical.riewr.cn
http://www.dtcms.com/a/281109.html

相关文章:

  • 一区 Top (HPJ) | WGAS+WGCNA分析文章套路
  • 零基础学软件测试:超详细软件测试基础理论知识讲解
  • 【实时Linux实战系列】使用系统调用实现实时同步
  • Java项目:基于SSM框架实现的学生档案管理系统【ssm+B/S架构+源码+数据库+毕业论文+开题报告】
  • 智能体技术深度解析:从概念到企业级搭建指南
  • 自学java,什么书比较好?
  • MaxKB使用笔记【持续ing】
  • LeetCode 1888. 使二进制字符串字符交替的最少反转次数
  • 维基框架发布 1.0.11 至中央仓,深化国产化 DevOps 生态整合
  • 3-Nodejs-使用fs文件系统模块
  • kotlin的自学笔记1
  • 文心一言开源版部署及多维度测评实例
  • Listener(监听器)
  • 拓扑排序一>可达性统计
  • [WUSTCTF2020]朴实无华
  • Vue 3的核心机制-解析事件流、DOM更新、数据请求、DOM操作规范及组件库DOM操作的解决方案
  • 日记_7.14_实际开发的进步
  • 使用Spring Cloud LoadBalancer报错java.lang.IllegalStateException
  • Wordpress登录数据库连接失败的问题
  • Web攻防-PHP反序列化字符逃逸增多减少成员变量属性解析不敏感Wakeup绕过
  • 网络:TCP序列号和滑动窗口,顺序保证
  • 【R语言】警告conversion failure on ‘中文字符‘ in ‘mbcsToSbcs‘: for 注 (U+6CE8)
  • 枪机、支持POE、4G连接交换机实现多屏幕显示
  • 【郑大二年级信安小学期】Day12:编写渗透测试脚本搭建虚拟环境
  • 淘宝扭蛋机小程序开发:重构电商娱乐化体验的新范式
  • 不同系统记录项目进度不一致,如何统一口径
  • 【Linux系统】命令行参数和环境变量
  • gitee某个分支合并到gitlab目标分支
  • 微信小程序未登录状态下的导航拦截有哪些方法可以实现
  • AI大模型应用架构演进:从LLM基础到Agent协作的范式转移