初始化堆栈上的多态变量

时间:2014-04-13 22:21:38

标签: c++ c

来到具有Java背景的C ++,我想通过使用两个实现中的一个A或{{1}初始化B类型的变量来设置一些多态代码。 }。

我的问题是,是否有一种简单的方法可以在堆栈上执行此操作。我有一个案例,我只在方法体内使用C,并且想要它在函数结束时被破坏,因此触摸堆是可选的。

以下是我在堆上的方式:

A

在实践中,我可能会将其解析为工厂方法,并使用A* a = NULL; if (p) { B* b = new B(); b->setSomethingImplementationSpecific(); a = b; } else { a = new C(); } doSomething(a); delete(a); 来避免auto_ptr

这可行,但我可以在堆栈上执行吗?我的思维模式是这样的:

delete(a)

现在我不必为A* a = NULL; if (p) { B b; b.setSomethingImplementationSpecific(); a = &b; } else { C c; a = &c; } doSomething(a); 而烦恼,但delete(a)无法工作,因为当doSomething(a)B被摧毁时超出范围。

我一直在尝试用三元运算符找出一种方法来完成它的一部分,但我最终都把语法和一个临时的地址搞定了 - 所以我是对的没有办法做到这一点?

C

关于在堆栈中实现多态性是否愚蠢的想法的建议是值得欢迎的,但主要是我试图更好地理解这个领域中C / C ++的限制,而不是设计感。

5 个答案:

答案 0 :(得分:4)

如果您使用的是C ++ 11,则可以获得"堆栈语义"使用unique_ptr

std::unique_ptr<A> a = (p ? new B() : new C());

虽然对象本身仍将在堆上分配。

std::auto_ptr<A>是C ++ 03中的等价习语。

答案 1 :(得分:3)

您可以使用std::aligned_union进行干净利落的存储:

template <typename...T>
using storage_t = typename std::aligned_union<0, T...>::type;

和自定义unique_ptr删除器:

struct placement_deleter {
  template <typename T>
  void operator () (T* ptr) const {
    ptr->~T();
  }
};

template <typename T>
using stack_ptr = std::unique_ptr<T, placement_deleter>;

导致使用:

storage_t<B, C> storage;
stack_ptr<A> a;
if (p) {
  auto b = new (&storage) B();
  a.reset(b);
  b->setSomethingImplementationSpecific();
} else {
  a.reset(new (&storage) C());
}

doSomething(*a);

See it live at Coliru

答案 2 :(得分:2)

而不是这个原始代码,

A* a = NULL;
if (p) {
  B* b = new B();
  b->setSomethingImplementationSpecific();
  a = b;
}
else {
  a = new C();
}

doSomething(a);
delete(a);

你可以这样做:

void doSomething( A const& ) {}

void doBeeDoo( B&& b )
{
    b.doSomethingImeplementationSpecific();
    doSomething( b );
}

void foo()
{
    if( p ) { doBeeDoo( B() ); } else { doSomething( C() ); }
}

答案 3 :(得分:2)

您可以使用boost::optional执行类似的操作:

#include <boost/optional.hpp>

void example(bool p) {
  boost::optional<B> b;
  boost::optional<C> c;
  A* a = nullptr;
  if (p) {
    b = B();
    b->setSomethingImplementationSpecific();
    a = b.get_ptr();
  }
  else {
    c = C();
    a = c.get_ptr();
  }
  doSomething(a);
}

请注意bc的生命周期必须足够长。但只有其中一个调用BC的构造函数和析构函数。

答案 4 :(得分:1)

你赢得了什么工作。到达b时,cdoSomething(a);将从堆栈中删除。但是,你可以这样做:

if (p) {
  B b;
  b.setSomethingImplementationSpecific();
  doSomething(&b);
}
else {
  C c;
  doSomething(&c);
}