首页 > 解决方案 > 在作为指针注入到类后重新创建堆栈对象是否不好?

问题描述

// Example program
#include <iostream>

class Foo{

public:  
  Foo(int a):a(a){}
  void print(){
      printf("%d\n",a);
  }

private: 
  int a;

};

class Bar{
public:
  Bar(Foo* foo):foo(foo){}
  void print(){
    foo->print();
  }

private:
  Foo* foo;
};

int main()
{
  Foo f = {10};
  Bar b(&f);
  b.print();
  f = {20};
  b.print();
}

在上面的代码中,与 Bar 对象共享的 Foo 对象可以在 Bar 不知道的情况下重新创建。想象一下,我必须将 bar 对象注入到第三个类中。现在我可以更新 foo 依赖项,而无需创建新的 bar 对象和第三个类。

这种模式是否普遍使用,是否违反了一些 OOP 原则?

标签: c++ooppointers

解决方案


我不认为代码做你认为它做的事情。我已经将默认构造函数和分配/运算符添加到您的 Foo 类中,并使用一些日志记录来查看会发生什么。除非您明确禁用它们,否则编译器会自动添加这些构造函数。请参阅此处的输出。

发生了什么

f = {20};

是您构造了一个不同的 Foo 对象,然后将其移动分配给原始实例。

在这种情况下,它相当于

f.a = 20;  // Assuming we make a public.

综上所述。如果您的用途只是更改现有实例中的字段(在这种情况下通过分配运算符)。然后一切都应该正常工作。这不一定会使 OOP 原则无效,除非您假设 Bar.foo 是恒定的或不变的。这通常称为组合,并且相当普遍(您的 UI 将包含可能从其他来源修改的各种按钮实例)。

如果您希望更改实现(例如 Foo 是一个虚拟类并且您希望替换不同的派生),那么在您的代码中您将需要有Foo* f = new Foo(10);. 您将拥有指针的副本,b并且分配将创建一个新类,该类不会更新b(类似于f = new FooDerived(20);.

要使其工作,您需要一个 Provider 类(这是一种 OOP 模式)。这将给你一个Foo. 最简单的是Foo**. 但最好有一些更可定制的东西。

也就是说,对于任何严肃的工作都尽量远离裸指针 ( Foo*)。酌情使用unique_ptr或shared_ptr,免得日后很多麻烦。


推荐阅读