C++;应用程序/程序设置的类? 使用VisualStudioC++与MFC。我正试图找出存储应用程序/程序设置的好方法。我不是指它们的持久存储,而是指代码中用于保存设置的数据结构
我创建了一个名为Settings的静态类,它有几个静态方法和嵌套类来划分设置。例如:C++;应用程序/程序设置的类? 使用VisualStudioC++与MFC。我正试图找出存储应用程序/程序设置的好方法。我不是指它们的持久存储,而是指代码中用于保存设置的数据结构,c++,visual-c++,configuration,mfc,settings,C++,Visual C++,Configuration,Mfc,Settings,我创建了一个名为Settings的静态类,它有几个静态方法和嵌套类来划分设置。例如: class Settings { public: Settings(void); ~Settings(void); static void SetConfigFile(const char * path); static CString GetConfigFilePath(); static void Load(); static void Save();
class Settings
{
public:
Settings(void);
~Settings(void);
static void SetConfigFile(const char * path);
static CString GetConfigFilePath();
static void Load();
static void Save();
class General
{
public:
static CString GetHomePage();
static void SetHomePage(const char * url);
private:
static int homePageUrl_;
};
private:
static CString configFilePath_;
};
然后,我可以在整个代码中访问我的设置,如:
Settings::General::GetHomePage();
现在我进入单元测试,我开始意识到静态类是不受欢迎的。所以我想把它变成一个基于实例的类。但是我必须管理嵌套的类实例,这很简单,但对于测试来说仍然有点麻烦。嵌套类的全部目的只是将设置分组到逻辑组中。我在争论基于字符串的设置类是否会更好,比如settings->get(“General.HomePage”),尽管我认为我更喜欢专用访问器方法的强类型
为了回答我的问题,什么样的数据结构才能保存支持直接单元测试的程序配置/设置?如果它适合您,您可以这样做。您可以放弃枚举,转到常量字符串,甚至自由格式字符串。枚举实际上也不必在类中定义。有很多方法可以做到这一点 如果您想要实现类别,另一个类可以使用模板对多个实例执行类似的操作来定义枚举类型 只是个主意
#include "stdafx.h"
#include <map>
#include <string>
#include <iostream>
using namespace std;
class Settings
{
public:
typedef enum
{
HomePageURL,
EmailAddress,
CellPhone
} SettingName;
private:
typedef map<SettingName, string> SettingCollection;
SettingCollection theSettings;
public:
string& operator[](const SettingName& theName)
{
return theSettings[theName];
}
void Load ()
{
theSettings[HomePageURL] = "http://localhost";
}
void Save ()
{
// Do whatever here
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Settings someSettings;
someSettings.Load ();
cout << someSettings [Settings::SettingName::HomePageURL] << endl;
return 0;
}
#包括“stdafx.h”
#包括
#包括
#包括
使用名称空间std;
班级设置
{
公众:
类型定义枚举
{
主页URL,
电邮地址:,
手机
}设置名称;
私人:
typedef地图设置集合;
设置收集这些设置;
公众:
字符串和运算符[](常量设置名称和名称)
{
返回设置[名称];
}
空荷载()
{
设置[主页URL]=”http://localhost";
}
作废保存()
{
//在这里做什么都行
}
};
int _tmain(int argc,_TCHAR*argv[]
{
设置一些设置;
Load();
cout我认为您的要求(1)提供对配置变量的类型安全访问;(2)使用“full.scoped.name”
语法指定配置变量的名称之间不必存在冲突。当然,您可以进行类型安全操作,例如:
const char * getString(const char * fullyScopedName);
int getInt(const char * fullyScopedName);
bool getBool(const char * fullyScopedName);
通过阅读《我的图书馆入门指南》(,)的第2章和第3章,您可能会找到一些灵感
编辑:我提到的Config4Cpp文档可能会为API设计提供灵感,但我后来意识到,如果您决定从头开始编写自己的配置类(而不是使用像Config4Cpp这样的第三方库),您可能会很感激关于实现选项的建议
您的类应该使用std::map
来存储fullyScopedName->值映射的集合。显然,fullyScopedName将是一个字符串,但是有两个选项用于表示值
第一个选项是将值表示为字符串。类型安全访问器,如getInt()
或getBool()
将从映射中检索基于字符串的值,然后对其进行解析以将其转换为所需的类型。如果解析失败,则访问器操作将引发异常。(这是Config4Cpp采用的方法。)
第二个选项是表示如下伪代码所示的值:
enum ValueType { STRING_VAL, INT_VAL, BOOL_VAL };
struct Value {
ValueType type;
union {
const char * stringVal;
int intVal;
bool boolVal;
} data;
};
然后,类型安全访问器的实现可以按如下方式编码(伪代码):
我现在使用的这个类主要受Nathan答案的启发,除了模板化方法:
class Settings {
public:
Settings(void);
virtual ~Settings(void);
enum SettingName { General_WindowWidth, General_HomePageUrl,
General_ShowDownloadsWindow, Privacy_RememberPasswords,
Privacy_RememberHistory };
virtual void SetConfigFile(const char * path);
virtual std::string GetConfigFilePath();
virtual void Load();
virtual void Save();
template<class T>
T Get(SettingName name) {
return boost::lexical_cast<T>(settings_[name]);
}
template<class T>
void Set(SettingName name, T value) {
settings_[name] = boost::lexical_cast<std::string>(value);
}
void Set(SettingName name, std::string value) {
settings_[name] = value;
}
private:
std::string configFilePath_;
std::map<SettingName, std::string> settings_;
};
类设置{
公众:
设置(无效);
虚拟设置(void);
枚举设置名称{General_WindowWidth,General_HomePageUrl,
一般\u show downloadswindow,隐私\u memberrpasswords,
隐私(记忆故事);;
虚拟void SetConfigFile(const char*path);
虚拟std::字符串GetConfigFilePath();
虚空荷载();
虚拟空保存();
模板
T Get(设置名称){
返回boost::词法转换(设置[name]);
}
模板
无效集(设置名称、T值){
设置\uu[name]=boost::词法\u转换(值);
}
无效集(设置名称、标准::字符串值){
设置u[name]=值;
}
私人:
std::string configFilePath\uux;
标准::地图设置;
};
使用typedef enum bla{}在C++声明中,你不需要写代码> EnUM BLA Value< /Cord>。<代码> BRAVARNEX满足。@ Rexx:在这个玩具例子中,我同意。但是,随着代码的演变,你发现模板模板不适合你的需求。ype或SettingCollection::key_type as types,这样,如果在一段复杂的代码中更改模板参数,则只需在一个位置更改类型。如果在类中使用了模板类型,并且这些类型本身就是模板,那么这也可以很好地工作。它还显示了类型的用途,因为在整个代码中使用的类型都是u他在地图上画了一条线。
class Settings {
public:
Settings(void);
virtual ~Settings(void);
enum SettingName { General_WindowWidth, General_HomePageUrl,
General_ShowDownloadsWindow, Privacy_RememberPasswords,
Privacy_RememberHistory };
virtual void SetConfigFile(const char * path);
virtual std::string GetConfigFilePath();
virtual void Load();
virtual void Save();
template<class T>
T Get(SettingName name) {
return boost::lexical_cast<T>(settings_[name]);
}
template<class T>
void Set(SettingName name, T value) {
settings_[name] = boost::lexical_cast<std::string>(value);
}
void Set(SettingName name, std::string value) {
settings_[name] = value;
}
private:
std::string configFilePath_;
std::map<SettingName, std::string> settings_;
};