c++在联合中继承实例



我有这个优化问题,我的程序经过配置阶段,然后是执行阶段。在配置过程中,选择一个函数的实现,然后在执行过程中的每次循环迭代时调用该函数。

我想避免在每个循环中通过switch/case来检查要调用哪个函数。解决方案是一个函数指针。现在每个函数都有一个内部状态。一个好的解决方案是继承,每个类实现do_something();基类的函数和编译器创建一个虚函数表,一切都很好。

现在,我还想优化内存使用。由于我每次总是使用一个实现,因此每个实例的内部状态可以共享相同的内存空间。这就成了一个问题,因为我不能将继承的实例放入联合中;编译器对此不高兴(我猜这是有意义的,可能是因为虚函数表)。

我发现这个问题的最佳解决方案是声明一个数据结构,该结构在类的外部使用联合,并将指向它的指针传递给类的每个实例。

有更好的方法吗?

编辑:在这种情况下,不使用动态分配。

见下面代码:

#include <stdio.h>
using namespace std;

class Base{
public:
virtual void doprint() = 0;
};
class ChildA : public Base{
public:
virtual void doprint(){
printf("I am A : %d",foo);
};
int foo;
};
class ChildB : public Base{
public:
virtual void doprint(){
printf("I am B : %u", bar);
};
unsigned int bar;
};
int main()
{
// Changing this for a struct works
union{
ChildA a;
ChildB b;
} u;
// Configure phase
u.a.foo = -10;
Base *pbase = &u.a;

// Exec phase
pbase->doprint();

return 0;
}

上面的代码使编译器说:error: union member ‘main()::::a’ with non-trivial ‘ChildA::ChildA()’

丑陋的解决方案

#include <stdio.h>
using namespace std;
union InternalData{
struct {
int foo;
} data_for_a;
struct {
unsigned int bar;
} data_for_b;
};

class Base{
public:
void init(InternalData *data)
{
m_data = data;
}
virtual void doprint() = 0;
protected:
InternalData* m_data;
};
class ChildA : public Base{
public:
virtual void doprint(){
printf("I am A : %d", m_data->data_for_a.foo);
};

};
class ChildB : public Base{
public:
virtual void doprint(){
printf("I am B : %u", m_data->data_for_b.bar);
};
};
int main()
{
ChildA a;
ChildB b;
InternalData internal_data;

// Configure phase
internal_data.data_for_a.foo = -10;
a.init(&internal_data);
Base *pbase = &a;

// Exec phase
pbase->doprint();

return 0;
}

你不会真的想要一个union(没有人真的想要一个union…)你真正想要的是一个放置你的实现的地方,并获得一个接口指针,并保证它在之后被正确地销毁。

std::variant< ChildA, ChildB> impl; //define buffer that correctly destroys
Base *pbase; //declare the Base pointer.
impl = ChildA{}; //assign it an implementation
pbase = std::get<ChildA>(impl); //assign pointer to that implementation

如果你的c++没有std::variant,那么你可以自己实现析构缓冲区的关键部分。一个最小的版本看起来像这样:

template<class Base, std::size_t size, std::size_t align>
class buffer {
static_assert(std::has_virtual_destructor_v<Base>);
std::aligned_storage_t<size, align> rawbuffer;
Base* pbase=0;
public:
~buffer() {if (pbase) pbase->~Base();};

Base* get() {return pbase;}

template<class T, class...Us>
Base* construct(Us&&...vs) {
static_assert(sizeof(T) <= sizeof(rawbuffer));
assert(pbase == nullptr);
pbase = new(reinterpret_cast<T*>(&rawbuffer)) T(std::forward<Us>(vs)...);
return pbase;
}
};

请注意,您几乎肯定希望您的Base具有virtual析构函数。https://coliru.stacked-crooked.com/a/4d08c8b3b9625988

最新更新