【问题标题】:C++ passing Object by reference in constructor and copy constructor confusionC++ 在构造函数中通过引用传递对象和复制构造函数混淆
【发布时间】:2017-09-11 17:09:28
【问题描述】:

我最近开始接触 C++,我的主要语言一直是 Java。

我希望能够在构造函数中传递对对象的引用,以便构造的对象可以使用传递的对象并对其进行更改。

在对该主题进行一些研究时,我遇到了复制构造函数,但我不太了解此操作是否严格需要它们以及它们首先真正完成了什么。

TLDR:我想学习如何在 C++ 中完成以下 Java 代码的等效操作。

Java 代码

class Master {
    private Slave slave;

    Master(Slave slave) {
        this.slave = slave;
    }

    public void doSomethingToSlave() {
        slave.doSomething();
    }

    public void changeSlave(Slave s) {
        this.slave = s;
    }
}

C++ 代码 ??? -我目前的尝试-

class Master {
   public:
      Master(Slave& slave);
      void doSomethingToSlave();
      void changeSlave(Slave& s);

   private:
       Slave& slave;  // Is this correct? Do I need to specify that it's a reference?

}

Master::Master(Slave& slave) { // Copy constructor needed?
    this->slave = slave;
}

Master::doSomethingToSlave() {
    slave.doSomething();
}

Master::changeSlave(Slave& s) {
    slave = s;
}

使用指针?

class Master {
  public:
      Master(Slave* slave);
      void doSomethingToSlave();
      void changeSlave(Slave* s);

  private:
      Slave* slave;  

}

Master::Master(Slave* slave) { 
    this->slave = slave;
}

Master::doSomethingToSlave() {
    slave.doSomething(); // How do I access the object at slave*? 
}

Master::changeSlave(Slave* s) {
    slave = s;
}

【问题讨论】:

  • 你不会通过尝试从 Java 代码转置来学习 C++——这两种语言几乎完全不同。你需要一本好的 C++ 教科书。
  • @NeilButterworth 我开始意识到这一点,但现在我只是在空闲时间从事一些小型 C++ 项目,以便在我深入研究文献之前更好地了解这门语言,这就是我使用 Java 所做的,它使学习 Java 的过程变得非常愉快。
  • @Daniel 这根本与复制构造函数无关。复制构造函数用于复制相同的 class 对象,例如Master(const Master& m) {...}
  • 您应该在此处使用指针。一旦一个引用被初始化,它将总是引用同一个对象。
  • @mcrlc 我添加了第三个使用指针的示例,问题是我真的不确定如何在 doSomethingToSlave() 方法中的指针 *slave 处访问对象.

标签: c++ constructor pass-by-reference


【解决方案1】:

这是我希望阐明行为的示例:

#include <iostream>
using namespace std;

class MyType {
    public:
    int value;
};

int main() {
    // value == 1
    MyType obj1{1};
    // initialize a reference to refer to obj1.
    MyType &ref = obj1;

    // value == 2
    MyType obj2{2};

    // ref refers to obj1.
    cout << "A. ref.value = " << ref.value << endl;
    // this actually reassigns the memory in obj1
    // to the memory from obj2.
    ref = obj2;
    cout << "B. obj1.value = " << obj1.value << endl;

    // value == 3
    MyType obj3{3};
    // initialize a pointer to point to obj3.
    MyType *ptr = &obj3;

    // ptr refers to obj3.
    cout << "C. ptr->value = " << ptr->value << endl;
    // now we're just reassigning the pointer value.
    // this is like Java reference assignment.
    // ptr now points to obj2.
    ptr = &obj2;
    cout << "D. obj3.value = " << obj3.value << endl;
    // now we're reassigning the memory at obj2 to
    // the memory from obj1.
    // this is what the C++ reference assignment is doing.
    *ptr = obj2;
    cout << "E. obj2.value = " << obj2.value << endl;

    return 0;
}

输出如下:

A.参考值 = 1
B. obj1.value = 2
C. ptr->value = 3
D. obj3.value = 3
E. obj2.value = 2

Java 引用实际上类似于 C++ 指针,但 Java 不允许您执行取消引用和赋值 *ptr = value

但是,我同意其他人的说法,即使用 Java 的编码风格接近 C++ 并不是一个好主意。现代 C++ 程序并不真正使用原始指针。它们使用智能指针或值对象,因为 C++ 没有垃圾收集。如果您正在传递原始指针,则很难准确确定何时需要销毁特定对象。

就你而言,我认为你会使用std::shared_ptr&lt;Slave&gt;

值对象类似于Slave slave;,如果它是在方法体中声明的,则它是堆栈分配的对象,或者如果它被声明为类或结构的成员,则它直接存储在对象的内存中。

【讨论】:

  • 感谢您的解释,这确实解决了一些问题。
【解决方案2】:

复制构造函数(ctor)用于复制对象,即创建相同类型的对象的副本,作为参数给出。

在你的情况下,

Master::Master(Slave& slave)

不是复制 ctor,Master 不需要复制 ctor。

但是,Slave 应该有一个复制 ctor 和一个赋值运算符,因为

Master::changeSlave(Slave& s) {
    slave = s;
}

这是因为您将s 的副本分配给slave 指向的对象。这可能不是您想要做的。要重新分配指针,请务必使用指针(而不是原始指针而不是原始指针)而不是引用,因为它不能重新分配。


有用的参考资料:

对我来说,C++ for Java Programmers,尤其是 C++ 和 Java 之间差异的总结,有助于从 Java 迁移到 C++。

关于克隆:虽然通常使用赋值运算符和常规 ctor,但克隆模式在 C++ 中也很有帮助。很好的例子可以在 More Effective C++ 的第 25 条中找到(虚拟化 ctor 和非成员函数)。

【讨论】:

  • 您好,感谢您的回答,Slave 中的 clone 方法返回一个独立对象,该对象是 Slave 的精确副本?这是 C++ 中的常见做法还是只是 Java 的事情?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-01
  • 1970-01-01
相关资源
最近更新 更多