【问题标题】:What's the preferred way to instantiate one class in another?在另一个类中实例化一个类的首选方法是什么?
【发布时间】:2020-10-09 17:24:40
【问题描述】:

非常基本的问题。与设计偏好有关,但我认为我遗漏了一些注意事项。

我想在另一个类中有一个类的实例。在我看来,我有 3 个选择:

  1. 将对象class2 放在class1 中,如下所示。这意味着它是在构造 class1 的实例时构造的。我的问题是它可能需要默认和/或复制构造函数?当我在下面实例化一个class1 对象时,它是否使用该构造函数构造class2_inst(args)?或者class2_inst 是否已经使用一些默认构造函数创建并且class2_inst(args) 行只是复制 一个匿名class2 对象?

    class class2 {
      public class2(args) {
        ...
      }
    }
    
    class class1 {
      protected class2 class2_inst;
      public class1(args) : class2_inst(args) {
        ...
      }
    }
    
  2. 我可以有一个指向class2的指针:

    class class2 {
      public class2(args) {
        ...
      }
    }
    
    class class1 {
       protected class2* class2_inst;
       public class1(args) {
        class2_inst = new class2(args);
        ...
       }
    }
    

    这样做的好处是 class2 在我明确调用 new 运算符之前不会被实例化。

  3. 然后是使用引用而不是指针:

    class class2 {
      public class2(args) {
        ...
      }
    }
    
    class class1 {
      protected class2& class2_inst;
      public class1(args) {
        class2_inst = new class2(args);
        ...
      }
    }
    

我希望class2_inst 的寿命与class1 相匹配。让class2_inst 住在class1 之外没有什么好笑的。所以参考可能是要走的路。

在这 3 种方法中,哪种方法是每个人的首选方法,为什么?

【问题讨论】:

  • 真的没有偏好,这完全取决于您的具体用例。
  • public class1(args) 不是有效的 C++
  • @user253751 显然,显示的代码只是伪代码,并不意味着按原样编译。
  • @RemyLebeau 那些 sn-ps 无论如何都没有意义......
  • 你说得对,我会改正的。

标签: c++ oop c++11 design-patterns


【解决方案1】:

你的例子有点倒退。我认为您的意思是:

class class2 {
  public:
    class2(args) {
      ...
    }
};

class class1 {
  protected:
    class2 class2_inst;

  public:
    class1(args) : class2_inst(args) {
      ...
    }
};
class class2 {
  public:
    class2(args) {
      ...
    }
};

class class1 {
  protected:
    class2* class2_inst;

  public:
    class1(args) {
      class2_inst = new class2(args);
      ...
    }
};
class class2 {
  public:
    class2(args) {
      ...
    }
};

class class1 {
  protected:
    class2& class2_inst;

  public:
    class1(args) {
      class2_inst = new class2(args);
      ...
    }
};

现在,话虽这么说:

  • 示例 1 可以很好地满足您的需求,并且是首选方法:“我希望 class2_inst 的生命周期与 class1 的生命周期相匹配。拥有 @987654328 没什么好笑的@住在class1 之外。”回答你的问题 - 是的,class2_inst(args) 将直接构造 class2_inst 成员,而不是默认构造它,然后将匿名 class2 对象复制到其中。见Constructors and member initializer lists

  • 示例 2 也可以工作,但要使其工作正确,您需要将析构函数添加到 class1delete 新的 class2 对象,并且您需要根据Rule of 3/5/0,还将复制/移动构造函数和复制/移动赋值运算符添加到class1 以正确复制/移动class2 对象。

    class class2 {
      public:
        class2(args) {
          ...
        }
    };
    
    class class1 {
      protected:
        class2* class2_inst;
    
      public:
        class1(args) {
          class2_inst = new class2(args);
          ...
        }
    
        class1(const class1 &src) {
          class2_inst = new class2(*(src.class2_inst));
          ...
        }
    
        class1(class1 &&src) {
          class2_inst = src.class2_inst;
          src.class2_inst = nullptr;
          ...
        }
    
        ~class1(args) {
          delete class2_inst;
        }
    
        class1& operator=(const class1 &rhs) {
          if (this != &rhs) {
            class1 tmp(rhs);
            std::swap(class2_inst, tmp.class2_inst);
          }
          return *this;
        }
    
        class1& operator=(class1 &&rhs) {
          class1 tmp(std::move(rhs));
          std::swap(class2_inst, tmp.class2_inst);
          return *this;
        }
    };
    

    您可以在示例 1 中免费获得所有这些功能,因为编译器会为您自动生成这些额外的方法。是的,在某些有效的情况下,对成员使用指针更有意义,但这个例子不是其中之一。

  • 示例 3 根本无效。您不能将对象指针分配给对象引用。为什么你会认为“references may be the way to go”?在这种情况下,它们不是。

因此,简而言之,您应该尽可能选择值语义,但在需要时使用指针/引用语义

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-23
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    • 2019-10-27
    • 2018-06-15
    • 1970-01-01
    相关资源
    最近更新 更多