【问题标题】:Pointers and Object Oriented Programming指针和面向对象编程
【发布时间】:2012-08-28 17:28:53
【问题描述】:

指针如何与面向对象编程的概念一起工作?

据我了解(请注意,我被归类为 ID-10T),OOP 的主要原则是包含在类中并保持管理责任(内存/实现/等);但是当一个对象的方法返回一个指针时,我们似乎正在“弹出”这个对象。现在,有人可能需要担心:

  1. 他们是否应该删除指针的关联对象?
  2. 但是如果类仍然需要对象呢?
  3. 他们可以更改对象吗?如果是这样,怎么做? (我知道const 可能会解决这个问题)
  4. 等等……

对象的用户现在似乎需要更多地了解类的工作原理以及类对用户的期望。感觉就像是“猫从袋子里出来”的场景,似乎是在给 OOP 打耳光。

注意:我注意到这是一个独立于语言的问题;但是,在 C++ 环境中工作时,系统提示我提问。

【问题讨论】:

  • 对于 C++11,原始指针应该用于表示无所有权。
  • 我会研究“const vs nonconst”、“pointer vs reference”、“lvalue vs rvalue”和std::unique_ptrstd::shared_ptrstd::weak_ptr。人们抱怨 C++ 中复杂的内存管理问题,这些问题在 Java 和 C# 等其他语言中被掩盖了 - 但是有一个好处:性能。

标签: c++ oop pointers responsibility


【解决方案1】:

您描述的是所有权问题。这些与面向对象是正交的(即独立的,你可以没有另一个,甚至两者都没有)。如果您不使用 OOP 并且不使用指向 POD 结构的指针,您也会遇到同样的问题。如果您使用 OOP,但以某种方式解决它,您就没有问题。您可以(尝试)使用更多的 OOP 或其他方式来解决它。

它们也与指针的使用正交(除非您选择并扩展指针的定义)。例如,如果两个不同的位置将索引保存到一个数组中并改变、调整大小并最终删除该数组,则会出现同样的问题。

在 C++ 中,通常的解决方案是选择正确的智能指针类型(例如,当您希望共享对象时返回共享指针,或表示独占所有权的唯一指针)以及大量文档。实际上,后者是任何语言的关键要素。

一个与 OOP 相关的 您可以做的事情是封装(当然,您可以在没有 OOP 的情况下进行封装)。例如,根本不公开对象,只公开查询引擎盖下的对象的方法。或者不公开原始指针,只公开智能指针。

【讨论】:

  • @MooingDuck 老实说,我对在这些情况下应该如何使用引用没有强烈的意见。我唯一的猜测是使用它们来指示非拥有临时访问权限? (另外,我的回答有一半以上与语言无关,很多语言甚至没有参考。)
【解决方案2】:

对于初学者......你不能没有指针或多态性 参考。在 C++ 中,传统上,对象是被复制的,并且具有(对于 大部分)自动存储时间。但复制不适用于 多态对象——它们往往会被切片。而且OO也经常 意味着身份,这反过来意味着你不想要复制。所以 解决方案是动态分配对象,并通过 围绕指针。你用它们做什么是设计的一部分:

如果对象在逻辑上是另一个对象的一部分,那么该对象是 负责它的生命周期,以及接收指针的对象 应采取措施确保他们在拥有后不使用它 对象消失。 (请注意,即使在具有 垃圾收集。只要你有一个对象就不会消失 指向它的指针,但是一旦拥有的对象无效,拥有的对象 也可能失效。垃圾收集器不会 回收内存并不能保证您指向的对象是 可用。)

如果对象本身是一等实体,而不是 逻辑上是另一个对象的一部分,那么它可能应该照顾 本身。同样,可能持有指向它的指针的其他对象必须是 通知它是否不再存在(或变得无效)。的使用 观察者模式是通常的解决方案。回到我开始 C++ 的时候,那里 是“关系管理”的一种时尚,具有某种 您注册关系的管理类,以及 据说可以确保一切正常。在实践中,他们 要么不起作用,要么只做简单的观察者 模式,而您今天再也听不到它们了。

在大多数情况下,您的确切问题是合同的一部分 每个类都必须为它的每个功能建立。对于真正的 OO 类(实体对象),你可能永远不应该删除它们:那是 有生意,不是你的。但也有例外:如果您正在交易 例如,对于事务,已删除的对象无法回滚, 所以当一个对象决定删除自己时,它通常会注册 这个事实与事务管理器,谁将删除它作为 提交,一旦确定,就不需要回滚了。作为 改变对象,这是合同的问题:在很多 应用程序中,有映射对象,用于映射 对象的某种外部标识符。带着目标,往往, 能够修改对象。

【讨论】:

    【解决方案3】:

    根据我的理解和经验,它通常围绕您正在尝试做的事情以及使用指针的语言(例如 C++ 与 Objective-C)。

    不过,通常,在 C++ 术语中,我发现最好通过引用返回对智能指针的引用(例如 std::shared_ptr)(甚至可能是 const 引用,具体取决于具体情况),或者只是将指针隐藏在类中,如果它需要被它之外的东西访问或使用,请使用 getter 方法来复制指针并返回它,或者返回对指针的引用(授予,AFAIK ref- to-ptr 只能在 C++ 中使用)。如果有人不知道你在大多数情况下不应该删除 ref-to-ptr(当然,如果它的释放是由类内部处理的),你真的应该三思而后行是否或者他们是否准备好在你的团队中做 C++ 的事情。

    如果类成员可以被堆栈分配(即,如果它们不会占用太多内存),那么只对类成员使用公共引用是相当普遍的,同时在内部管理堆分配的对象。如果您需要在类之外设置类成员,可以只使用一个获取所需值的 set 方法,而不是直接访问它。

    【讨论】:

    • 我能想到的类返回原始指针的唯一原因是它是否需要通过NULL 向可能不存在的成员返回非拥有的“引用”。在所有其他情况下,应返回引用、智能指针或值。没有理由返回对原始指针的引用。
    • @MooingDuck - 单身呢?我宁愿能够通过对指针的引用来管理共享实例,而不是自己处理原始指针。这样,我就不用担心用完后释放内存。
    • 我认为 OO 对象由任何常用的智能指针管理是相当罕见的。 MooningDuck 关于返回引用而不是指针的建议在一定程度上是有效的,但它违背了 OO 的传统,如果你想在不同的时间处理几个不同的对象,那就很尴尬了;引用不能被重新定位,所以你最终使用一个指针,并获取引用的地址。 (当然,智能指针很少适用于 OO 类型的对象。)
    • @aboutblank:抛开关于是否应该从单例开始的争论,没有理由为单例设置 any 指针。使用参考。
    • @JamesKanze:我的陈述是在返回值的上下文中,因为这就是我解释问题的方式。没错,如果您需要重新定位对类成员的本地“引用”,那么这需要是一个原始指针。我看不出返回引用而不是指针如何以任何方式违反 OO 传统。并且智能指针几乎总是适用于 OO 类型的对象。
    猜你喜欢
    • 2018-06-23
    • 2020-05-18
    • 1970-01-01
    • 2023-02-09
    • 2010-09-18
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多