C ++ имеет два конструктора копирования, как по ссылке, так и по значению? - PullRequest
1 голос
/ 08 декабря 2011

Рассмотрим этот кусок кода:

class complex{
        private:
                double re, im;
        public:
                complex(double _re, double _im):re(_re),im(_im){}
                complex(complex c):re(c.re),im(c.im){}
};

Я уже знал, что конструктор копирования complex(complex c) вызовет бесконечную рекурсию.

Однако в качестве функции для копирования следует выбрать только конструктор копирования с константной ссылкой complex(const complex &c), поскольку это поведение по умолчанию, если оно не указано явно. Все остальное исключено, например complex(complex c).

Почему здесь применяется функция с передачей по значению? Или оба являются конструкторами копирования, за исключением того, что передача по значению не может быть изменена и используется для передачи другим функциям, а не ее конструктору?

Я думаю, в Java это разрешено делать, поскольку он просто скопирует объект в конструктор.

Ответы [ 3 ]

3 голосов
/ 09 декабря 2011

Конструктор копирования должен быть в одной из следующих форм:

T(T&);
T(const T&);

То есть конструктор является конструктором копирования * только 1007 * если он принимает один параметр типа ссылочного класса.Конструктор, который принимает один параметр типа класса по значению, по определению не является конструктором копирования (правка) - и фактически является недопустимым, как указано в Cat Plus Plus.

12.1: Конструкторы

10 / Конструктор копирования для класса X - это конструктор с первым параметром типа X & или типа const X &

Однако за пределами этого стандартафундаментальная ошибка в вашем понимании конструктора копирования.Рассмотрим следующий код:

class Foo
{
public:
  Foo() {}
  Foo(Foo f) {/*...*/};
};

int main()
{
  Foo f1;
  Foo f2(f1);
}

Когда создается f2, f1 передается по значению.Чтобы оценить параметры для вызова конструктора, необходимо скопировать f1.Итак, вы видите, что здесь есть парадокс.Чтобы вызвать конструктор копирования, вы должны сделать копию.Чтобы сделать копию, вы должны вызвать конструктор копирования ...

Выше необходимо вызвать конструктор с аргументом by-value просто потому, что это тип параметра , равный : это Foo по значению.Если бы это было не по значению, это должно быть либо по ссылке, которая выглядит так:

Foo(Foo& rhs)
/* or like this: */ Foo(const Foo& rhs);

... или она должна принимать это по указателю, который выглядит так:

Foo(Foo* prhs)

... но в последнем случае это, очевидно, не конструктор копирования, учитывая приведенное выше определение.

2 голосов
/ 09 декабря 2011

complex(complex) не является конструктором копирования.Это плохо сформировано, и должно быть отклонено компилятором.Не существует бесконечной рекурсии, потому что вы просто не можете определить такой конструктор.

Не шаблонный конструктор для класса X является конструктором копирования, если его первый параметр имеет тип X &, const X &, volatileX & или const volatile X &, и либо нет других параметров, либо все остальные параметры имеют аргументы по умолчанию (8.3.6).

Объявление конструктора для класса X некорректно, если его первый параметримеет тип (необязательно cv-квалифицированный) X и либо нет других параметров, либо все остальные параметры имеют аргументы по умолчанию.Шаблон функции-члена никогда не создается для создания такой сигнатуры конструктора.

1 голос
/ 09 декабря 2011

Ответ на вопрос Java, поскольку даны все другие возможные объяснения:

//java code

public class Bar{
  private int foo;

  public Bar() { } // public no-args constructor
  public Bar(Bar b) { foo = b.foo; }  // copy constructor
}

В Java объекты являются ссылками, а не объектами значений, как в C ++.В C ++, когда вы копируете объект, вы создаете копию состояния объекта, внутренних переменных и т. Д. В Java он просто копирует ссылку.Состояние объекта не копируется, поэтому на самом деле нет необходимости вызывать конструктор копирования, как вы делаете это в C ++.

...