【问题标题】:Coming from Java, learning C++ - understanding pointers at functions来自Java,学习C++——理解函数指针
【发布时间】:2012-09-06 08:12:47
【问题描述】:

我已经阅读了一个针对想要学习 C++ 的 Java 开发人员的快速教程。它只解释了 C++ 的基本原理(和语法)(我猜)。起初我以为我已经完全理解了一切,但是在编写 C++ 时出现了一些我不太清楚的问题。

...之间有什么区别

ExampleClass* doSomething(ExampleClass* ec) {}

ExampleClass* doSomething(ExampleClass& ec) {}

ExampleClass& doSomething(ExampleClass* ec) {}

ExampleClass& doSomething(ExampleClass& ec) {}

?

【问题讨论】:

  • 获取an introductory C++ book,在学习 C++ 时忘记 Java。我是认真的; Java 和 C++ 只是表面上相似。试图像理解 Java 一样理解 C++非常会适得其反。这样的书会谈到指针和引用,这就是你的问题所在。
  • 只需将引用视为指针,它无法更改它们指向的对象(常量指针),当您使用它时会自动取消引用。

标签: java c++ function pointers reference


【解决方案1】:

指针和引用有相似之处。它们都指向或引用一个对象,而没有空间来表示对象本身的值。然而,指针显式地使用* 来取消引用(作为一元运算符),并使用& 来获取对象的地址。 * 也用于不同的上下文中,以指定指针类型。

引用是一个更安全的“自动”指针。然而,引用是不可变的,因为它以后不能更改为指向其他东西。引用也使用& 符号,但在不同的上下文中。它不是一元运算符,而是用于指定引用类型。

第一个示例接受一个指向 ExampleClass 的指针并返回一个指向 ExampleClass 对象的指针。例如。你可能会说:

ExampleClass* doSomething(ExampleClass* ec) {
  return ec;
}
ExampleClass * pointer = new ExampleClass();
ExampleClass * anotherpointer = doSomething(pointer);

相比之下,下面这个引用了 ExampleClass。引用就像一个指针,但它意味着你不传递指针类型的东西,直接传递它,例如:

ExampleClass* doSomething(ExampleClass& ec) {
  return &ec; // & unary operator - get the address of ec
}

ExampleClass obj = ExampleClass();
ExampleClass* pointer = doSomething(obj); // it will automatically get a reference to the input object

下一个例子接受一个指针并返回一个引用(注意返回类型不是指针):

ExampleClass& doSomething(ExampleClass* ec) {
  // note ec of is type ExampleClass*
  // *ec is of type ExampleClass
  return *ec; // returns a reference to whatever the pointer points to
}
ExampleClass * pointer = new ExampleClass();
ExampleClass& myobj = doSomething(pointer);

你只需将它传递给一个引用对象(它指向函数给定的对象,即不复制)。请注意,在这种情况下,函数应该注意确保为对象分配了空间,并且不需要在 return 语句中显式引用(使用 *)该对象。

我想你可以算出最后一个例子:

ExampleClass& doSomething(ExampleClass& ec) {}

请注意,在返回引用时,您必须确保被引用的对象在函数上下文之外分配空间(例如,作为全局变量或静态局部变量),以便它不会被破坏。

你不应该返回一个对局部变量的引用,它会在函数退出时被销毁,例如:

ExampleClass& doSomething(ExampleClass* ec) {
  ExampleClass copy = *ec;
  return copy; // WARNING: returning reference to object that will be destroyed
}

【讨论】:

    【解决方案2】:
    ExampleClass* doSomething(ExampleClass* ec) {}
    

    以指针为参数,返回指针。

    ExampleClass* doSomething(ExampleClass& ec) {}
    

    通过引用获取一个对象并返回一个指针。

    ExampleClass& doSomething(ExampleClass* ec) {}
    

    将指针作为参数并返回一个引用。

    ExampleClass& doSomething(ExampleClass& ec) {}
    

    通过引用获取一个对象并返回一个引用。

    请注意,通过引用返回很棘手,因为它很容易导致未定义的行为。通过引用返回本地对象是非法的:

    ExampleClass& doSomething() 
    {
        ExampleClass x;
        return x;
    }
    

    这将编译(您可能会收到警告),但x 在函数结束后被销毁,因此您将得到一个无效的引用。要使其有效,x 需要在函数结束后仍然存在(如果它是类成员,直到对象本身被销毁,或者它可以是 static 本地的,或动态分配的)。

    同样的情况也可能发生在指针上,虽然不太常见:

    ExampleClass* doSomething() 
    {
        ExampleClass x;
        return &x;
    }
    

    【讨论】:

      【解决方案3】:

      在 C++ 中传递指向对象的指针和通过引用传递对象之间没有真正的区别。然而,通过引用传递允许更简单的运算符重载语法,并消除了对大量 -> 无处不在的需求,应该是首选。

      当通过引用传递对象时,不希望方法能够更改对象是很常见的。这是通过将对象参数声明为 const 引用 (const myClass&) 来实现的。

      【讨论】:

      • 我认为差异远不止简化运算符和避免-> 语法。您不能像删除指针一样删除对对象的引用。您不能像拥有空指针一样拥有空引用(否则为未定义的行为)。考虑所有权语义,指针意味着对象的严格所有权,而引用意味着您可以观察/操作对象但您不拥有它(因此您不能删除它)。此外,该标准不要求引用具有存储空间,因此假设引用只是指针周围的语法糖可能会产生误导。
      【解决方案4】:
      ExampleClass* doSomething(ExampleClass* ec) {}
      

      函数做一些事情来获取值和返回值

      ExampleClass* doSomething(ExampleClass& ec) {}
      

      函数在内存中获取对象地址并返回值

      ExampleClass& doSomething(ExampleClass* ec) {}
      

      函数做一些事情来获取值并返回内存中对象的地址

      ExampleClass& doSomething(ExampleClass& ec) {}
      

      函数做一些事情,获取并返回内存中对象的对象地址

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-18
        • 2011-11-14
        • 2013-06-28
        • 2011-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多