Почему один ctor не может назвать другой ctor для инициализации объекта

class Foo {

 public:
  Foo() { Foo(1)}
  Foo(int x, int y = 0):i(x) {}
 private:
  int i;
}

Кто-либо может дать мне некоторый reasonas о, я могу сделать это? Если не, почему?

6
задан skydoor 16 March 2010 в 18:01
поделиться

5 ответов

Потому что спецификация языка не допускает этого. Таков язык. Очень раздражает, если вы привыкли к Java или другим языкам, которые это позволяют. Однако через некоторое время к этому привыкаешь. У всех языков есть свои особенности, это всего лишь одна из особенностей C ++. Я уверен, что у авторов спецификаций есть свои причины.

Наилучший способ обойти это, что я нашел, - это создать общую функцию инициализации и заставить ее вызывать оба конструктора.

Примерно так:

class Foo {
public:
    Foo() {initialize(1);}
    Foo(int nX) { initialize(nx); }

private:
    void initialize(int nx) { x=nx; }
    int x;
};
10
ответ дан 8 December 2019 в 12:58
поделиться

Это выбор языка дизайна.

Конструктор - это однократная (для каждого объекта) операция, которая создает новый объект в неинициализированной памяти. Для объекта может быть вызван только один конструктор, после его завершения начинается жизненный цикл объекта, и никакой другой конструктор не может быть вызван или возобновлен для этого объекта.

На другом конце своего жизненного цикла деструктор может быть вызван (корректно) только один раз для каждого объекта, и как только деструктор введен, время жизни объекта заканчивается.

Основной причиной этого является указание явным образом, когда деструктор объекта будет запущен и в каком состоянии он может ожидать объект.

Если конструктор класса завершается успешно, то он вызывается деструктором, в противном случае объект время жизни никогда не начиналось, и деструктор не вызывается. Эта гарантия может быть важна, когда объект получает ресурсы в своем конструкторе, которые необходимо освободить в его деструкторе. Если получение ресурса не удается, конструктор обычно не работает; если деструктор все равно запустился, он может попытаться освободить ресурс, который никогда не был успешно получен.

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

Для простоты правил уничтожения проще, если каждый объект создается одним конструктором и - в случае успешного создания - уничтожается одним деструктором.

Обратите внимание, что в C ++ 11 конструктор может делегировать другому конструктору, но есть ограничения, которые на самом деле не ослабляют принципала одной конструкции для каждого объекта. (Главный конструктор может перенаправить к целевому конструктору, но если он это делает, он не должен называть ничего другого (базовые классы или члены) в своем списке инициализаторов. Они будут инициализированы целевым конструктором, как только целевой конструктор вернет тело Основной конструктор завершится (дальнейшая инициализация). Невозможно воссоздать какие-либо базы или члены, хотя он позволяет вам совместно использовать код конструктора между конструкторами.)

4
ответ дан 8 December 2019 в 12:58
поделиться

Вы не можете этого сделать. См. Раздел 10.3: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3 . Вы можете попробовать это сделать, но при этом будет создан новый временный объект (не этот), который будет уничтожен после перехода управления.

Однако вы можете создать частную функцию, которая инициализирует переменные, которую может вызывать конструктор по умолчанию или параметризованный конструктор.

2
ответ дан 8 December 2019 в 12:58
поделиться

Есть действительно отвратительный хак, который я видел для вызова другого ctor. Он использует операцию placement new для указателя this. erk

Вот так:

Class::Class(int x) : x_(x) {}
Class::Class() {
    new (this) Class(0);
}
Class::Class(const Class &other) : x_(other.x_) {}
Class& operator=(const Class &other) {
    new (this) Class(other);
    return *this;
}

Обратите внимание, что я не рекомендую это делать, и я не знаю, какие ужасные последствия это может иметь для структур C++, таких как виртуальные базовые классы и т.д. Но я ожидаю, что они есть.

2
ответ дан 8 December 2019 в 12:58
поделиться

Хотя согласно стандартам производители вольны реализовывать связывание данных по-своему, если мы рассмотрим наиболее популярную реализацию: этот указатель, мы можем увидеть причину, почему это не может быть реализовано.

Предположим, что у вас есть класс:

class A
{
    public:
    A(){}
    A(int a){}
} ;

С реализацией this pointer этот класс будет выглядеть примерно так:

class A
{
    public:
    A(A *this){}
    A(A *this,int a){}
} ;

Обычно вы создаете объекты так:

A ob ;

Теперь, когда компилятор видит это, он выделяет память для этого и передает адрес этого выделенного блока памяти конструктору A, который затем создает объект. Он будет пытаться делать то же самое каждый раз для каждого вызываемого конструктора.

Теперь, когда вы пытаетесь вызвать конструктор внутри другого конструктора, вместо выделения новой памяти компилятор должен передать текущему объекту this. Отсюда несогласованность!

Другая причина, которую я вижу, заключается в том, что даже если вы хотите вызвать конструктор внутри другого конструктора, вы все равно хотите, чтобы конструктор вызывал конструкторы по умолчанию для всех объектов в классе. Теперь, если один конструктор вызывает другой, то конструирование по умолчанию должно происходить для первого конструктора, а не для последующих. Реализация такого поведения означает, что будет несколько перестановок, которые необходимо обработать. Если этого не сделать, то ухудшится производительность, так как каждый конструктор будет по умолчанию конструировать все вложенные объекты.

Вот что я могу придумать в качестве возможных причин такого поведения и не имею никаких стандартов для поддержки.

0
ответ дан 8 December 2019 в 12:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: