来到具有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 ++的限制,而不是设计感。
答案 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);
答案 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);
}
请注意b
和c
的生命周期必须足够长。但只有其中一个调用B
或C
的构造函数和析构函数。
答案 4 :(得分:1)
你赢得了什么工作。到达b
时,c
和doSomething(a);
将从堆栈中删除。但是,你可以这样做:
if (p) {
B b;
b.setSomethingImplementationSpecific();
doSomething(&b);
}
else {
C c;
doSomething(&c);
}