C++ 中构造函数和模板参数之间的依赖注入权衡?

Dependency injection tradeoff between constructor and template parameters in C++?

我想知道何时通过构造函数使用依赖注入以及何时使用模板参数.

例子

我有以下 class 定义

  1. Interface:
/// Interface class
class Interface {
 public:
  virtual void Method() = 0;
  virtual ~Interface() = default;
};
  1. Concrete:
/// Concrete class
class Concrete : public Interface {
 public:
  void Method() override { std::cout << "Concrete.Method()\n"; }
  static void StaticMethod() { std::cout << "Concrete.StaticMethod()\n"; }
};
  1. ConstructorDI 通过构造函数依赖于 Interface
/// Class with constructor dependency injection
class ConstructorDI {
 public:
  explicit ConstructorDI(Interface &interface) : interface_(interface) {
    std::cout << "** ConstructorDI() **" << std::endl;
    // Call the Method() exposed by the interface
    interface_.Method();
  }

 private:
  // Interface-based dependency (this class doesn't own the underlying concrete
  // type)
  Interface &interface_;
};
  1. TemplateDI 依赖于 typename T
/// Class with template dependency injection
template <typename T>
class TemplateDI {
 public:
  TemplateDI() { 
      std::cout << "** TemplateDI() **" << std::endl;
      // Call the Method()
      t_.Method(); 
      // Call the StaticMethod()
      T::StaticMethod();
}

 private:
  // Type-based dependency (this class owns the concrete type)
  // Thus, cannot be a Interface (pure abstract) class
  T t_;
};

上面的典型用法如下example:

// Concrete class implementing the Interface class
Concrete concrete;

// Create a class using dependency injection via constructor
ConstructorDI constructor_d_i(concrete);

// Create a class using dependency injection via template
TemplateDI<Concrete> template_d_i;

产生以下输出:

** ConstructorDI() **
Concrete.Method()
** TemplateDI() **
Concrete.Method()
Concrete.StaticMethod()

观察

问题

要在这两种类型之间进行权衡,我想知道:

使用模板与基于继承的多态总是有同样的权衡:模板实例化发生在编译时,因此允许编译时多态行为。

基于继承的多态性发生在运行时。因此,例如,您可以存储指向您在编译时不知道其类型的对象的指针集合,例如

//...
std::vector<Interface*> some_stuff = get_heterogeneous_concrete_types();
std::vector<ConstructorDI> di_objects;
std::transform(some_stuff.begin(), some_stuff.end(), std::back_inserter(di_objects),
    [](auto* p) { return ConstructorDI(*p); }
);
//...

如果您有多个在具体类型上参数化的 DI 类型,则不能执行上述操作。但是如果你不需要那种行为,模板化版本会更有效率,等等。