【问题标题】:Pointer as member or Reference as member指针作为成员或引用作为成员
【发布时间】:2012-03-22 17:13:32
【问题描述】:

我需要在 c++ linux 中澄清一下。

我有class C1 和另一个class C2C1 将有 C2 的引用。

class C1
{

   C2 &obj ;

}

我在这里考虑两个选择,

  1. 直接持有C2的引用为C2 &obj;
  2. 创建C2的指针,为c2* obj;

哪个好?有什么区别呢?什么时候选择?

【问题讨论】:

标签: c++


【解决方案1】:

两者都不好。如果你有任何指针 引用成员变量指向在你的类之外分配的东西,这很可能意味着程序设计存在某种缺陷。

我可以提出一个合理的情况,即当您拥有某种特殊的外部垃圾收集器功能时。 (例如 C++ Builder 在堆上自动分配/释放 VCL 组件。)

另一种情况是它可能有效,即当您使用 C++ 类模拟 C 结构时,或者在另一个类中编写私有类时。

但最有可能的是,需要指出课堂之外的东西来自有缺陷的程序设计。我会三思而后行为什么我的代码需要这样做,并且至少尝试为指针添加尽可能多的 const 正确性,即const *c2 const obj;

如果你有这样特殊的成员指针,你很可能还必须为你的类手动编写一个复制构造函数、赋值运算符和析构函数。

编辑:为什么这是不好的做法的基本原理是称为private encapsulation 的概念,它是称为object-oriented design 的程序设计概念的基石之一。

【讨论】:

  • “指向课堂之外的东西的需要来自有缺陷的程序设计”。我强烈反对。
  • 你的意思是说任何使用图表的程序都设计得很糟糕吗?使用指针进行导航的设计很糟糕?我的观点几乎相反:如果你在类中分配一些东西,通常更合适的是让对象本身成为一个成员。指针是为类外分配的东西保留的。
  • @JamesKanze 什么是“图表”?这可能意味着任何事情,尽管我认为您的意思是典型的 ADT,称为“图形”。例如,图的所有节点(顶点)都应该分配在图类中。如果声明为图的私有子类,则节点类可以公开指向图类的指针。用户不需要关心原始指针,他们应该通过公共成员函数导航图表。
  • 图表可以是任何对象引用其他对象(和返回)的情况。不一定有图类;事实上,通常没有图形类。并且使用公共成员函数并不能解决任何问题;如果你要在对象之间导航,那么你要去的对象必须包含一个指向你要去的对象的指针(或指向其他一些包含指向你要去的对象的指针的对象)。
  • @JamesKanze 调用者会期望诸如 next()、previous()、up()、down() 之类的函数。为什么调用者会关心对象分配在哪个地址?一个来自现实世界的例子,一个我制作的链表类。节点对象具有公开的“next”和“prev”指针,但节点类是链表的私有类。公共成员函数将具有诸如“add”、“remove”、“find”、“change”、“traverse”之类的名称。因此,调用者无需在对象之间导航。事实上,调用者并不关心类是如何实现的。
【解决方案2】:

你要使用哪一个,取决于你到底需要什么。

例如,如果您需要某种依赖注入,则可以使用引用成员变量。即使这样,您也可以使用指针。但是,请记住,具有引用成员的类通常应该是不可复制的。

在大多数情况下,您应该使用指针或值成员变量。

【讨论】:

  • 引用使对象不可赋值,但仍然可以复制。 (但我同意您的基本观点:大多数时候,更喜欢指向类类型中的引用的指针。除非该类型已经不可复制。)
  • @JamesKanze 是的。美滋滋的说。我关于不可复制的想法是该类继承自 boost::noncopyable。在这种情况下,它也是不可分配的。但你明白我的意思
【解决方案3】:

指针对引用有两个主要优点。指针可以为空并且可以移动指针(例如使用 ++ 运算符)。 搬家对你没有帮助。 如果在实例化 C1 时您的类 C2 未知,那么您应该使用指针,因为您无法初始化引用,但可以将指针初始化为 null。

就像 Als 所说,我还建议在 C2 实例可能发生变化时使用指针。在这种情况下您可以使用引用,但我认为指针是一种“更清洁”的解决方案。

【讨论】:

  • 指针不必初始化不是优点。
【解决方案4】:

尽可能避免使用引用成员。

此处适用与引用和指针相同的差异,
如果您有一个引用成员,那么它必须在创建类对象时进行初始化,您不能像指针成员那样进行延迟初始化,因为引用不能为 NULL 并且不能重新安装,而可以在需要时使指针成员懒惰地指向C2 实例。

另外,请注意还有其他副作用,一旦你有一个引用成员,编译器将不会生成复制赋值运算符(=)&你必须自己提供一个,确定什么是复杂的在这种情况下,您的 = 运营商应采取的行动。

对于大多数实际目的(除非您真的担心由于 C2 大小而导致的高内存使用),只需将 C2 的实例作为 C1 的成员就足够了,而不是指针或引用成员,这可以为您节省很多担心引用/指针成员带来的其他问题,尽管以额外的内存使用为代价。

如果必须,请使用指针,确保使用智能指针而不是原始指针,这样使用指针会让您的生活更轻松。

【讨论】:

  • 由于您提到的确切原因,使用指针比使用引用作为成员更可取。使用参考是一种不太通用的解决方案,可能会导致令人惊讶的行为。我建议始终避免使用引用作为成员。
  • 我要补充一点,在某些情况下,引用的限制完全符合您试图用代码描述的内容,即在其整个生命周期内与另一个对象关联的对象(例如例如,带有互斥对象的互斥锁对象)。在这种情况下,使用引用更为明确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 2013-08-16
  • 1970-01-01
相关资源
最近更新 更多