首页 > 解决方案 > 类成员和依赖注入的对象与引用

问题描述

我是 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,因为我发现它是最熟悉和最直观的。

我在这里找到了类似的讨论讨论,但更多的是关于指针与引用。

标签: c++dependency-injection

解决方案


在这方面,C# 和 C++ 之间的主要区别之一是,在 C# 中类是引用类型,而在 C++ 中它们是值类型。

方法 1 和 2 基于复制构造。如果传递给构造函数的对象恰好是B. 但是,如果您使用 B 的派生类,它可能会由于对象切片而失败。如果源对象是常量,方法 2 也可能会失败。

方法3:不再考虑(在您的问题中划伤)

方法4:可以,只要通过引用传递的对象继续存在,只要该对象。但是,如果 functionB::Bar()不是虚函数,则B::Bar()始终会在 中调用Foo(),即使您使用从 B 派生的类及其自己的Bar().

方法 5:使用智能指针并克隆通过引用传递的对象(使用clone()成员或使用模板构造函数):

class A
{
  private:
    unique_ptr<B> _b;
  public:
    template<class T>A(const T&b): _b(make_unique<T>(b)) { }

    void Foo()
    {
        _b->Bar();
    }
};

在线演示


推荐阅读