我需要实现很多具有不同 const 成员数据的派生类。数据处理应该在基类中处理,但我找不到访问派生数据的优雅方法。下面的代码可以运行,但我真的不喜欢它。
代码需要在小型嵌入式环境中运行,因此无法广泛使用堆或 Boost 等花哨的库。
class Base
{
public:
struct SomeInfo
{
const char *name;
const f32_t value;
};
void iterateInfo()
{
// I would love to just write
// for(const auto& info : c_myInfo) {...}
u8_t len = 0;
const auto *returnedInfo = getDerivedInfo(len);
for (int i = 0; i < len; i++)
{
DPRINTF("Name: %s - Value: %f \n", returnedInfo[i].name, returnedInfo[i].value);
}
}
virtual const SomeInfo* getDerivedInfo(u8_t &length) = 0;
};
class DerivedA : public Base
{
public:
const SomeInfo c_myInfo[2] { {"NameA1", 1.1f}, {"NameA2", 1.2f} };
virtual const SomeInfo* getDerivedInfo(u8_t &length) override
{
// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;
}
};
class DerivedB : public Base
{
public:
const SomeInfo c_myInfo[3] { {"NameB1", 2.1f}, {"NameB2", 2.2f}, {"NameB2", 2.3f} };
virtual const SomeInfo *getDerivedInfo(u8_t &length) override
{
// Duplicated code in every derived implementation....
length = sizeof(c_myInfo) / sizeof(c_myInfo[0]);
return c_myInfo;
}
};
DerivedA instanceA;
DerivedB instanceB;
instanceA.iterateInfo();
instanceB.iterateInfo();
最佳答案
您在这里不需要任何虚拟或模板。只需将 SomeInfo*
指针及其长度添加到 Base
,并提供一个 protected 构造函数来初始化它们(由于没有默认构造函数,因此不可能忘记初始化它们)。
构造函数被保护不是硬性要求,但由于 Base
不再是抽象基类,使构造函数 protected 会阻止 Base
被实例化。
class Base
{
public:
struct SomeInfo
{
const char *name;
const f32_t value;
};
void iterateInfo()
{
for (int i = 0; i < c_info_len; ++i) {
DPRINTF("Name: %s - Value: %f \n", c_info[i].name,
c_info[i].value);
}
}
protected:
explicit Base(const SomeInfo* info, int len) noexcept
: c_info(info)
, c_info_len(len)
{ }
private:
const SomeInfo* c_info;
int c_info_len;
};
class DerivedA : public Base
{
public:
DerivedA() noexcept
: Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))
{ }
private:
const SomeInfo c_myInfo[2] { {"NameA1", 1.1f}, {"NameA2", 1.2f} };
};
class DerivedB : public Base
{
public:
DerivedB() noexcept
: Base(c_myInfo, sizeof(c_myInfo) / sizeof(c_myInfo[0]))
{ }
private:
const SomeInfo c_myInfo[3] {
{"NameB1", 2.1f},
{"NameB2", 2.2f},
{"NameB2", 2.3f}
};
};
您当然可以使用小型、零开销的包装器/适配器类来代替 c_info
和 c_info_len
成员,以提供更好和更安全的访问(例如 begin()
和 end()
支持),但这超出了这个答案的范围。
正如 Peter Cordes 指出的那样,这种方法的一个问题是,如果您的最终代码仍然使用虚拟对象(virtual你没有在你的帖子中展示过的函数。)如果没有虚拟对象,那么对象大小只会增加一个int
。您确实说过您在一个小型嵌入式环境中,因此如果这些对象中有很多同时处于事件状态,那么这可能需要担心。
Peter 还指出,由于您的 c_myInfo
数组是 const
并且 使用常量初始化器,因此您不妨将它们设为 static
。这会将每个派生对象的大小减少数组的大小。
关于c++ - 如何消除这种与继承相关的代码异味?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56627438/