C ++在构造函数和复制构造函数混淆中通过引用传递Object

时间:2017-04-15 16:33:43

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

我最近开始使用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;
}

2 个答案:

答案 0 :(得分:0)

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

在你的情况下,

Master::Master(Slave& slave)

不是复制文件,Master不需要复制文件。

但是,由于

Slave应该有一个副本ctor和一个赋值运算符
Master::changeSlave(Slave& s) {
    slave = s;
}

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

有用的参考资料:

对我来说,C++ for Java Programmers,特别是C ++和Java之间差异的总结,已经帮助从Java转向C ++。

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

答案 1 :(得分:0)

这是一个我希望阐明这种行为的例子:

#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. ref.value = 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<Slave>

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