2

我想知道将对象实例作为另一个类的成员变量处理的最佳实践是什么。在阅读了不同的帖子之后,似乎应该避免将对象引用作为成员变量,但我不确定使用指针是否是一个好的解决方案。另一种可能性是拥有const引用作为类构造函数的参数,然后使用复制构造函数来初始化成员变量。

  • 处理这种情况的经验法则是什么?
  • 怎么用share_ptr用作成员变量怎么样
  • 如果成员变量引用抽象类怎么办?在这种情况下,还有其他替代指针或引用的方法吗?

编辑:

由于问题的答案实际上取决于上下文,因此我将在类成员引用抽象类的情况下指定它。例如,考虑以下实现策略模式的代码:

 class Client{

        // reference to Abstract strategy
        void execute(){
             strategy.doStuff();
        }
 }

 class AbstractStrategy{

 public:
      virtual void doStuff() = 0;
 }

 class ConcreteStrategy{
      void doStuff(){}
 }

由于AsbtractStrategy具有纯虚函数,因此将其作为成员的唯一方法似乎Client是使用指针或引用。有更好的解决方案吗?

4

2 回答 2

2

你的问题没有单一的答案。您需要考虑的因素是对象生命周期。如果对象 A 以某种形式“包含”对象 B,则对象 B 需要比对象 A 寿命更长或“发生坏事”。

智能指针 (shared_ptr, unique_ptr) 让对象 A 强制执行规则,即对象 B 在对象 A 完成之前不能被删除,因此它们是一个好主意。

将对象 B 复制到对象 A 也为对象 B 的生命周期提供了必要的保证,但您需要注意现在有两个单独的对象 B。这是否可以接受由您决定。

指针和引用通常是有问题的,因为 A 无法控制 B 的生命周期,但有时程序的整体结构意味着这不是问题。

简介:了解您的对象生命周期并了解您可以使用哪些工具。

于 2015-03-12T15:25:30.897 回答
2

(甚至是原始的)指针肯定没有错。你只需要负责。如果您希望更改它引用的对象,请通过指针实现该成员,否则添加另一个间接级别是没有意义的,将其作为常规成员变量在内存使用和 CPU 时间方面都会更有效.

一个Person类的age成员应该是一个数字,而不是一个指针,但一个人的residence可能是一个指针,以引用住宅集合中的一个对象。并且并不总是需要人来管理住宅或使用智能指针,住宅数据层可能完全独立于人员层,住宅与人一起删除没有什么意义,而是应该只是变得空置。

这一切都取决于您需要什么,对象是否需要成为某物,拥有某物或仅引用外部的某物。

请记住,间接是有代价的。这就是为什么将age成员实现为指针毫无意义的原因,人们不会活很长时间,你可以用一个字节来存储年龄,如果你有一个年龄集合,你将一无所获您为每个人引用一个,因为指针通常是 4 或 8 个字节,加上它引用的字节,您会浪费内存和 CPU 时间来检索该内存地址中的数据。但是住宅可能是一个大对象,加上它与人的耦合并不紧密,因此将人的住宅实现为指针是有意义的。虽然智能指针会在人被删除时删除住所,但常规指针只会允许您从住所的居民引用中注销该人'

还要考虑这一点 - 您可能在对象之间有抽象,例如,您可能并不真的希望每个人都有一个住宅指针,或者在多个住宅的情况下有多个,实际上一个人可能对住宅的存在一无所知,您仍然可以通过使用第三个对象来建立人与住所之间的关系,而无需保留诸如成员之类的对象,例如对象和住所指针的地图,因此您可以通过查询地图获得一个人的住所(如果有) ,它会比为每个人都有一个居住指针要慢,但它会节省内存,因为它不会为每个人的实例存储居住指针。它可能根本没有住所。

至于抽象类——因为它们不能被实例化,你不能有一个作为成员对象。由于这个想法是定义一个接口,你很可能是一个指针并利用虚拟调度和多态性。请注意,除了聚合之外,您还可以使用继承。如果每个对象只有一个策略,并且每个对象都有它,那么聚合和继承都可以解决问题。在某些对象有多个而其他对象没有的情况下,您可以采用上一段中提到的解耦设计。另请注意,使用继承Strategy::doStuff()将成为该对象的 vtable 的一部分,这意味着该特定类型的每个对象最终都将执行相同的代码,而使用聚合或其他耦合,可以在每个实例基础上设置策略。

于 2015-03-12T15:26:57.577 回答