如何在堆栈上创建多态对象?

use*_*229 8 c++ polymorphism stack

如何在堆栈上分配多态对象?我正在尝试做类似的事情(试图避免使用new分配堆)?:

A* a = NULL;

switch (some_var)
{
case 1:
    a = A();
    break;
case 2:
    a = B(); // B is derived from A
    break;
default:
    a = C(); // C is derived from A
    break;
}
Run Code Online (Sandbox Code Playgroud)

R. *_*des 7

免责声明:我绝对不认为这是一个很好的解决方案.好的解决方案是重新考虑设计(假设存在有限数量的可能性,可能不保证OO多态性?),或者使用第二个函数通过引用传递所述多态对象.

但是,由于其他人提到这个想法,但错误的细节,我发布这个答案,以显示如何正确.希望我做对了.

很明显,可能类型的数量是有界的.这意味着一个有区别的联盟,就像boost::variant可以解决问题一样,即使它不漂亮:

boost::variant<A, B, C> thingy = 
    some_var == 1? static_cast<A&&>(A())
    : some_var == 2? static_cast<A&&>(B())
    : static_cast<A&&>(C());
Run Code Online (Sandbox Code Playgroud)

事实上现在你可以使用像静态访问者这样的东西,如果让我觉得这不是OO多态的好用.

如果您不想使用现成的解决方案,而是希望按照其他答案中的建议手动使用新的位置,则需要注意许多事项,因为我们在此过程中丢失了常规自动对象的一些属性:

  • 编译器不再给我们正确的大小和对齐;
  • 我们不再自动调用析构函数;

在C++ 11中,这些都很容易修复aligned_unionunique_ptr.

std::aligned_union<A, B, C>::type thingy;
A* ptr;
switch (some_var)
{
case 1:
    ptr = ::new(&thingy.a) A();
    break;
case 2:
    ptr = ::new(&thingy.b) B();
    break;
default:
    ptr = ::new(&thingy.c) C();
    break;
}
std::unique_ptr<A, void(*)(A*)> guard { ptr, [](A* a) { a->~A(); } };
// all this mechanism is a great candidate for encapsulation in a class of its own
// but boost::variant already exists, so...
Run Code Online (Sandbox Code Playgroud)

对于不支持这些功能的编译器,您可以获得替代方案:Boost包含aligned_storagealignment_of可用于构建的特征aligned_union; 并且unique_ptr可以替换为某种范围防护等级.

现在这已经不在了,只是如此清楚,不要这样做,只是简单地传递给另一个功能,或者完全重新审视设计.


Mik*_*our 7

您不能将单个函数构造成这样的工作,因为在条件块内创建的自动或临时对象的生命周期不能扩展到包含块中.

我建议将多态行为重构为一个单独的函数:

void do_something(A&&);

switch (some_var)
{
case 1:
    do_something(A());
    break;
case 2:
    do_something(B()); // B is derived from A
    break;
default:
    do_something(C()); // C is derived from A
    break;
}
Run Code Online (Sandbox Code Playgroud)