初始化堆栈上的多态变量 使用java背景来C++,我想通过初始化A的变量,用两个实现之一,B或C.初始化一些多态代码。

初始化堆栈上的多态变量 使用java背景来C++,我想通过初始化A的变量,用两个实现之一,B或C.初始化一些多态代码。,c++,c,C++,C,我的问题是,是否有一种简单的方法可以在堆栈上实现这一点。我有一个例子,我只在方法体中使用了一个,并且希望在函数末尾销毁它,所以触摸堆是可选的 下面是我将如何在堆上执行此操作: A* a = NULL; if (p) { B* b = new B(); b->setSomethingImplementationSpecific(); a = b; } else { a = new C(); } doSomething(a); delete(a); 在实践中,我可能会将其拉

我的问题是,是否有一种简单的方法可以在堆栈上实现这一点。我有一个例子,我只在方法体中使用了一个,并且希望在函数末尾销毁它,所以触摸堆是可选的

下面是我将如何在堆上执行此操作:

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

doSomething(a);
delete(a);
在实践中,我可能会将其拉到工厂方法中,并使用auto_ptr来避免deletea

这行得通,但我能在堆栈上做吗?我的思维模式是这样的:

A* a = NULL;
if (p) {
  B b;
  b.setSomethingImplementationSpecific();
  a = &b;
}
else {
  C c;
  a = &c;
}

doSomething(a);
现在我不必为deletea费心了,但是doSomethinga不起作用,因为B或C在超出范围时会被破坏

我一直在试图找到一种方法,用三元运算符来完成其中的一部分,但我最终还是破坏了语法,并获取了一个临时变量的地址——所以我说没有办法做到这一点,对吗

A * const a = &(p ? B() : C());
首先在堆栈上实现多态性是否是一个愚蠢想法的建议是受欢迎的,但我主要是试图更好地理解C/C++在这一领域的局限性,独立于设计意义。

您所拥有的将不起作用。当您到达doSomethinga;时,b和c将从堆栈中删除;。但是,您可以这样做:

if (p) {
  B b;
  b.setSomethingImplementationSpecific();
  doSomething(&b);
}
else {
  C c;
  doSomething(&c);
}
你所拥有的不会起作用。当您到达doSomethinga;时,b和c将从堆栈中删除;。但是,您可以这样做:

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

如果您使用的是C++11,则可以使用唯一的\u ptr获取堆栈语义:

尽管对象本身仍将在堆上分配


std::auto_ptr是C++03中的等效惯用法。

如果您使用的是C++11,则可以通过使用唯一的_ptr来获得堆栈语义:

尽管对象本身仍将在堆上分配


std::auto_ptr是C++03中的等效惯用法。

而不是此原始代码

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() ); }
}

而不是原来的代码

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() ); }
}

您可以使用boost::optional执行以下操作:


请注意,b和c必须具有足够长的寿命。但它们中只有一个调用B或C的构造函数和析构函数。

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


请注意,b和c必须具有足够长的寿命。但其中只有一个调用了B或C的构造函数和析构函数。

您可以使用存储干净地执行此操作:

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

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);

.

您可以使用以下清洁方式进行存储:

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

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);

.

谢谢。我已经想到了,但我希望避免重复打电话给doSomething。谢谢。我曾想过,但希望避免重复调用doSomething.-1 Re const A&A=p?B:C;,虽然引用绑定确实是这样工作的,但选择操作符却不是这样。@Cheersandhth.-Alf:更正。该修复程序会处理选择操作符的类型要求,但是你确定生命周期和UB吗?这就是我在编写引用绑定时的意思。但是,choice操作符不是这样工作的。如果你对一个函数实参这样做,那么你在技术上是安全的,因为这些临时变量一直持续到完整表达式的末尾。初始值设定项的子表达式中的临时值也具有该生存期。这有点太短了。@Cheersandhth.-Alf:嗯,现在我又不确定了。。。示例:我尝试过的每一个编译器在这个示例中都做了正确的事情,甚至对-Wall也没有抱怨。当然,这并不能证明什么,但让我不确定标准要求什么。我想我应该把这当作一个问题。-1关于a&a=p?B:C;,虽然引用绑定确实是这样工作的,但选择操作符却不是这样。@Cheersandhth.-Alf:更正。该修复程序会处理选择操作符的类型要求,但是你确定生命周期和UB吗?这就是我在编写引用绑定时的意思。但是,choice操作符不是这样工作的。如果你对一个函数实参这样做,那么你在技术上是安全的,因为这些临时变量一直持续到完整表达式的末尾。初始值设定项的子表达式中的临时值也具有该生存期。这有点太短了。@Cheersandhth.-Alf:嗯,现在我又不确定了。。。示例:我尝试过的每一个编译器在这个示例中都做了正确的事情,甚至对-Wall也没有抱怨。当然,这并不能证明什么,但让我不确定标准要求什么。我想我应该把这个问题变成一个问题。这最接近于我最初想象的干净,避免了杰夫回答中的尝试。不过,在实践中,我采用了尼莫的答案,使用堆;在设置SomethingImplementationSpecific;之前;。如果该方法抛出,我们确实希望调用~B。这最接近于我最初设想的干净操作,并避免了try-catch
杰夫的回答。不过,在实践中,我采用了尼莫的答案,使用堆;在设置SomethingImplementationSpecific;之前;。如果该方法抛出,我们确实希望调用~B。boost::option的实现使用placement new将内容保留在堆栈上。因此,这与公认的答案非常相似,但需要为a B和C分配内存,即使只使用了其中一个。boost::option的实现使用placement new将内容保留在堆栈上。因此,这与公认的答案非常相似,但需要为a B和C分配内存,即使只使用其中一个。