考虑以下 C++ 类:
// An abstract fruit that can be sliced
class AbstractFruit
{
public:
virtual void Slice() = 0;
};
// A lemon (concrete implementation of AbstractFruit)
class Lemon : public AbstractFruit
{
int size; // small medium large
public:
Lemon(int size) : size(size) {}
virtual void Slice() override { /* slice it */ }
};
// A pie uses a fruit reference
class Pie
{
AbstractFruit& fruit;
public:
Pie(AbstractFruit& fruit) : fruit(fruit) {}
};
一切正常。
出于向后兼容的原因,Pie API 需要有一个创建柠檬派的构造函数:
Pie(int size) : fruit(Lemon(size)) {}
这行不通。据我所知,我正在构造函数的参数列表中创建一个新的 Lemon 实例,并用它初始化水果引用。但是,Lemon 实例在那之后立即被销毁,留下 fruit 引用指向一个被销毁的对象。
完成这项工作的最佳方法是什么?
我知道我可以将 Pie 切换为使用指针而不是引用,但我想尽可能使用引用。
最佳答案
如果 Pie
对象的大小不重要,一种可能的解决方案是让 Pie
管理可选的 Lemon
:
class Pie
{
std::optional<Lemon> lemon_;
AbstractFruit& fruit_;
public:
Pie(AbstractFruit& fruit) : fruit_(fruit) {}
Pie(int size) : lemon_(size), fruit_(*lemon_) {}
};
std::optional
是可选的,std::unique_ptr
可以代替:
class Pie
{
std::unique_ptr<Lemon> lemon_;
AbstractFruit& fruit_;
public:
Pie(AbstractFruit& fruit) : fruit_(fruit) {}
Pie(int size) : lemon_(std::make_unique<Lemon>(size)), fruit_(*lemon_) {}
};
在第一种情况下,Lemon
将存储在 Pie
本身中,在第二种情况下,Lemon
将分配在堆上,并且Pie
将只存储指向它的指针。如果 Lemon
尺寸较小 (<= sizeof(void*)
),std::optional
是更好的选择。
注意成员是initialized in order of declaration in the class ,这就是为什么 lemon_
声明应该在 fruit_
声明之前。
关于C++ 在构造函数中用表达式初始化引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58888943/