在 C++ 中包装 stdint 变量的基础和继承对象
Base and inherited objects to wrap stdint variables in C++
我正在为使用 Sloeber(Eclipse 的 Arduino 插件)的 AVR 项目重构一些 C++ 代码。项目中有很多"settings"个变量存储在EEPROM中,有上限和下限,需要字符串标签等。这些设置是不同的整数类型(uint8_t
、int32_t
等) ,我想要一个可以包含这些类型中的任何一种的包装器,其中一些方法是从基础 class 继承的。我还希望能够形成所有设置变量的单个数组,以便我可以遍历它们。
一个简单的实现演示如下:
// Base class storing a uint8_t by default
class Base {
public:
typedef uint8_t numType;
numType value = 0;
};
// Child class changing 'numType' to a uint16_t
class Child: public Base {
public:
typedef uint16_t numType;
};
然后运行以下内容:
Base baseObj;
baseObj.value = 123;
Child childObj;
childObj.value = 12345;
我的意图是 childObj.value
将成为 uint16_t
,而 baseObj.value
仍将是 uint8_t
。
但是 childObj.value
的计算结果为 57
,因此它仍被视为 uint8_t
。对实现这种事情的方法有什么想法吗?
除非 child-classes 会有其他独特的行为,否则您只需要将 Base
作为 模板:
template<typename T>
struct Base
{
using numType = T;
numType value = 0;
};
然后您可以为您想要的不同整数类型创建 type-aliases:
using Uint8 = Base<uint8_t>;
using Uint16 = Base<uint16_t>;
你想要的是一种类型擦除的形式。您可以直接使用 std::any
(如果您只存储一个值,这将有意义)或构建您自己的:
class Setting {
public:
Setting(std::string description) : _description(description) {}
virtual ~Setting() = 0;
std::string getDescription();
template<typename T>
T getValue();
private:
std::string _description;
};
template <typename T>
class SettingTyped : public Setting {
public:
SettingTyped(T value, std::string description)
: Setting(description), _value(value) {}
T getValue() { return _value; }
private:
T _value;
};
Setting::~Setting() = default;
template<typename T>
T Setting::getValue()
{
auto* typedSetting = dynamic_cast<SettingTyped<T>*>(this);
if (!typedSetting)
throw std::runtime_error("Accessing with wrong type!");
return typedSetting->getValue();
}
template<typename T>
auto makeSetting(T value, std::string description)
{
return std::make_unique<SettingTyped<T>>(value, description);
}
bool foo() {
std::vector<std::unique_ptr<Setting>> settings;
settings.push_back(makeSetting<int>(3, "a setting"));
return (settings[0]->getValue<int>() == 3);
}
你可以玩这个来弄清楚如何区分 "prototype setting"(默认值,边界)和 "current setting value"(实际存储的值)。例如,您仍然可以决定边界是否应该在设置类型中编码(并且您为每种设置创建一个单独的类型)或者边界是否(可能)在每个实例中都是不同的常量。您的问题对此的要求不清楚。
特别不清楚您希望如何在遍历每个设置时知道它们的正确类型。此处假定您以某种方式知道(例如,根据描述?)。
我正在为使用 Sloeber(Eclipse 的 Arduino 插件)的 AVR 项目重构一些 C++ 代码。项目中有很多"settings"个变量存储在EEPROM中,有上限和下限,需要字符串标签等。这些设置是不同的整数类型(uint8_t
、int32_t
等) ,我想要一个可以包含这些类型中的任何一种的包装器,其中一些方法是从基础 class 继承的。我还希望能够形成所有设置变量的单个数组,以便我可以遍历它们。
一个简单的实现演示如下:
// Base class storing a uint8_t by default
class Base {
public:
typedef uint8_t numType;
numType value = 0;
};
// Child class changing 'numType' to a uint16_t
class Child: public Base {
public:
typedef uint16_t numType;
};
然后运行以下内容:
Base baseObj;
baseObj.value = 123;
Child childObj;
childObj.value = 12345;
我的意图是 childObj.value
将成为 uint16_t
,而 baseObj.value
仍将是 uint8_t
。
但是 childObj.value
的计算结果为 57
,因此它仍被视为 uint8_t
。对实现这种事情的方法有什么想法吗?
除非 child-classes 会有其他独特的行为,否则您只需要将 Base
作为 模板:
template<typename T>
struct Base
{
using numType = T;
numType value = 0;
};
然后您可以为您想要的不同整数类型创建 type-aliases:
using Uint8 = Base<uint8_t>;
using Uint16 = Base<uint16_t>;
你想要的是一种类型擦除的形式。您可以直接使用 std::any
(如果您只存储一个值,这将有意义)或构建您自己的:
class Setting {
public:
Setting(std::string description) : _description(description) {}
virtual ~Setting() = 0;
std::string getDescription();
template<typename T>
T getValue();
private:
std::string _description;
};
template <typename T>
class SettingTyped : public Setting {
public:
SettingTyped(T value, std::string description)
: Setting(description), _value(value) {}
T getValue() { return _value; }
private:
T _value;
};
Setting::~Setting() = default;
template<typename T>
T Setting::getValue()
{
auto* typedSetting = dynamic_cast<SettingTyped<T>*>(this);
if (!typedSetting)
throw std::runtime_error("Accessing with wrong type!");
return typedSetting->getValue();
}
template<typename T>
auto makeSetting(T value, std::string description)
{
return std::make_unique<SettingTyped<T>>(value, description);
}
bool foo() {
std::vector<std::unique_ptr<Setting>> settings;
settings.push_back(makeSetting<int>(3, "a setting"));
return (settings[0]->getValue<int>() == 3);
}
你可以玩这个来弄清楚如何区分 "prototype setting"(默认值,边界)和 "current setting value"(实际存储的值)。例如,您仍然可以决定边界是否应该在设置类型中编码(并且您为每种设置创建一个单独的类型)或者边界是否(可能)在每个实例中都是不同的常量。您的问题对此的要求不清楚。
特别不清楚您希望如何在遍历每个设置时知道它们的正确类型。此处假定您以某种方式知道(例如,根据描述?)。