【发布时间】:2019-11-17 00:25:05
【问题描述】:
我是 C++ 新手,具有 C# 背景。我正在尝试在 C++ 中使用 C# 中常用的依赖注入,我对声明依赖项并将它们传递的不同方式以及为什么我会使用其中一种方式感到困惑。假设A 依赖于B。
方法 #1 - 声明为对象并获取对象
class A
{
private:
B _b;
public:
A(B b): _b(b) { }
void Foo()
{
_b.Bar();
}
}
方法 #2 - 声明为对象并引用
class A
{
private:
B _b;
public:
A(B &b): _b(b) { }
void Foo()
{
_b.Bar();
}
}
方法 #3 - 声明为引用并获取对象 - 从头开始 - 未定义的行为
class A
{
private:
B &_b;
public:
A(B b): _b(b) { }
void Foo()
{
_b.Bar();
}
}
方法 #4 - 声明为引用并获取引用
class A
{
private:
B &_b;
public:
A(B &b): _b(b) { }
void Foo()
{
_b.Bar();
}
}
我已经尝试了以上所有方法,它们似乎都有效。它们之间有什么区别吗?如果是这样,我为什么要选择一个而不是另一个?我的偏好是 #1,因为我发现它是最熟悉和最直观的。
我发现了一个类似的讨论讨论 here,但更多的是关于指针与引用。
【问题讨论】:
-
如果
b在a之前消失,那么方法4 会造成麻烦,因为你有一个悬空的引用。 -
1 和 2 因为slicing 而无用。 3 是undefined behavior,4 可以工作但根本不安全,因为引用可能会悬空。如果你坚持使用依赖注入,你应该使用智能指针
-
感谢所有 cmets。我现在看到 3 恰好工作。我仍然没有完全理解 #1 和 #2 的切片问题,但我正在阅读它。
-
@alterigel 1 和 2 之间有什么区别吗?
-
@YetAnotherCoder 1 和 2 都存储您传递给构造函数的对象的 副本。这可能不是你想要的。在任何情况下,您都不能将派生自
B的类传递给构造函数,因为复制到基类类型将 slice,这意味着只复制对象的基础部分。这实际上意味着您不能在方法 1 或 2 中传递除B之外的任何类型。这似乎也不像依赖注入应该如何工作。