Неявный конструктор копии C++ для класса, который содержит другие объекты

И ради полноты, ссылки на регистрацию Scott Hanselman, которая содержит некоторые дополнительные подсказки также:

Добавляют главный экран iPhone Icons и Корректируют ViewPort

47
задан Ben Voigt 8 February 2011 в 00:46
поделиться

5 ответов

Foo f1;
Foo f2(f1);

Да, это будет делать то, что вы ожидаете:
Вызывается конструктор копирования f2 Foo :: Foo (Foo const &).
Эта копия создает свой базовый класс, а затем каждый член (рекурсивно)

Если вы определяете класс следующим образом:

class X: public Y
{
    private:
        int     m_a;
        char*   m_b;
        Z       m_c;
};

Следующие методы будут определены вашим компилятором.

  • Конструктор (по умолчанию) (2 версии)
  • Конструктор (Копия)
  • Деструктор (по умолчанию)
  • Оператор присваивания

Конструктор: По умолчанию:

Фактически существует два конструктора по умолчанию.
Один используется для инициализации нулем , а другой используется для инициализации значения . Используемое значение зависит от того, используете ли вы () во время инициализации или нет.

// Zero-Initialization compiler generated constructor
X::X()
    :Y()                // Calls the base constructor
                        //     If this is compiler generated use 
                        //     the `Zero-Initialization version'
    ,m_a(0)             // Default construction of basic PODS zeros them
    ,m_b(0)             // 
    m_c()               // Calls the default constructor of Z
                        //     If this is compiler generated use 
                        //     the `Zero-Initialization version'
{
}

// Value-Initialization compiler generated constructor
X::X()
    :Y()                // Calls the base constructor
                        //     If this is compiler generated use 
                        //     the `Value-Initialization version'
    //,m_a()            // Default construction of basic PODS does nothing
    //,m_b()            // The values are un-initialized.
    m_c()               // Calls the default constructor of Z
                        //     If this is compiler generated use 
                        //     the `Value-Initialization version'
{
}

Примечания: Если базовый класс или какие-либо члены не имеют действительного видимого конструктора по умолчанию, конструктор по умолчанию не может быть сгенерирован. Это не ошибка, если ваш код не пытается использовать конструктор по умолчанию (тогда только ошибка времени компиляции).

Конструктор (Копия)

X::X(X const& copy)
    :Y(copy)            // Calls the base copy constructor
    ,m_a(copy.m_a)      // Calls each members copy constructor
    ,m_b(copy.m_b)
    ,m_c(copy.m_c)
{}

Примечания: Если базовый класс или какие-либо члены не имеют допустимого конструктора видимой копии тогда конструктор копирования не может быть сгенерирован. Это не ошибка, если только ваш код не пытается использовать конструктор копирования (тогда только ошибка времени компиляции).

Оператор присваивания

X& operator=(X const& copy)
{
    Y::operator=(copy); // Calls the base assignment operator
    m_a = copy.m_a;     // Calls each members assignment operator
    m_b = copy.m_b;
    m_c = copy.m_c;

    return *this;
}

Примечания: Если базовый класс или какие-либо члены не имеют допустимого жизнеспособного оператора присваивания, тогда оператор присваивания не может быть сгенерирован. Это не ошибка, если только ваш код не пытается использовать оператор присваивания (тогда только ошибка времени компиляции).

Деструктор

X::~X()
{
                        // First runs the destructor code
}
    // This is psudo code.
    // But the equiv of this code happens in every destructor
    m_c.~Z();           // Calls the destructor for each member
    // m_b              // PODs and pointers destructors do nothing
    // m_a          
    ~Y();               // Call the base class destructor
  • Если объявлен любой конструктор (включая копию), то конструктором по умолчанию является не реализован компилятором.
  • Если конструктор копирования объявлен, компилятор не сгенерирует его.
  • Если объявлен оператор присваивания, компилятор не сгенерирует его.
  • Если деструктор объявлен компилятором не будет генерировать его.

Глядя на ваш код, генерируются следующие конструкторы копирования:

Foo::Foo(Foo const& copy)
    :bar(copy.bar)
{}

Bar::Bar(Bar const& copy)
    :i(copy.i)
    ,baz(copy.baz)
{}

Baz::Baz(Baz const& copy)
    :j(copy.j)
{}
68
ответ дан 26 November 2019 в 19:42
поделиться

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

То же самое верно для оператора присваивания и деструктора, BTW. Однако для конструктора по умолчанию он отличается: он предоставляется компилятором только в том случае, если вы сами не объявляете какой-либо другой конструктор.

11
ответ дан 26 November 2019 в 19:42
поделиться

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

2
ответ дан 26 November 2019 в 19:42
поделиться

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

1
ответ дан 26 November 2019 в 19:42
поделиться

Компилятор сгенерирует для вас необходимые конструкторы.

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

Используя ваш пример:

class Baz {
    Baz(const Baz& b) {}
    int j;
};
class Bar {
    int i;
    Baz baz;
};
class Foo {
    Bar bar;
};

Попытка создать экземпляр по умолчанию или скопировать конструкцию Foo вызовет ошибку, поскольку Baz не может быть сконструирован копированием, и компилятор не может сгенерировать конструкцию по умолчанию и скопируйте конструктор для Foo.

0
ответ дан 26 November 2019 в 19:42
поделиться
Другие вопросы по тегам:

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