对象作为C ++中类的成员变量

时间:2015-03-12 15:16:27

标签: c++ pointers reference shared-ptr member-variables

我想知道将对象实例作为另一个类的成员变量处理的最佳做法是什么。 在阅读不同的帖子之后,似乎应该避免将对象作为成员变量引用,但我不确定使用指针是否是一个很好的解决方案。另一种可能性是将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成员的唯一方法似乎是使用指针或引用。有更好的解决方案吗?

2 个答案:

答案 0 :(得分:2)

您的问题没有单一的答案。您需要考虑的因素是对象生命周期。如果对象A"包含"对象B以某种形式存在,那么对象B需要比对象A更长寿命或者#34; Bad Things Happen"。

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

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

指针和参考文献一般都存在问题,因为A无法控制B的生命周期,但有时程序的整体结构意味着这不是问题。

摘要:了解您的对象生命周期并了解可用的工具。

答案 1 :(得分:1)

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

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

这一切都取决于你需要什么,对象需要是什么,有什么东西或仅仅是引用外部的东西。

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

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

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