Почему неявный конструктор копирования вызывает конструктор копирования базового класса, а определенный конструктор копирования - нет? - PullRequest
35 голосов
/ 07 февраля 2012

Рассмотрим иерархию классов, где A является базовым классом, а B является производным от A.

Если конструктор копирования не определен в B, компилятор его синтезирует. При вызове этот конструктор копирования вызовет конструктор копирования базового класса (даже синтезированный, если он не был предоставлен пользователем).

#include <iostream>

class A {
    int a;
public:
    A() {
        std::cout << "A::Default constructor" << std::endl;
    }

    A(const A& rhs) {
        std::cout << "A::Copy constructor" << std::endl;
    }
};

class B : public A {
    int b;
public:
    B() {
        std::cout << "B::Default constructor" << std::endl;
    }
};

int main(int argc, const char *argv[])
{
    std::cout << "Creating B" << std::endl;
    B b1;
    std::cout << "Creating B by copy" << std::endl;
    B b2(b1);
    return 0;
}

Выход:

Creating B
A::Default constructor
B::Default constructor
Creating B by copy
A::Copy constructor

Если пользователь определяет свой собственный конструктор копирования в B, то при вызове этот конструктор копирования будет вызывать конструктор по умолчанию базового класса , если явно не указан вызов конструктора копирования базового класса (например, в списке инициализации).

#include <iostream>

class A {
    int a;
public:
    A() {
        std::cout << "A::Default constructor" << std::endl;
    }

    A(const A& rhs) {
        std::cout << "A::Copy constructor" << std::endl;
    }
};

class B : public A {
    int b;
public:
    B() {
        std::cout << "B::Default constructor" << std::endl;
    }
    B(const B& rhs) {
        std::cout << "B::Copy constructor" << std::endl;
    }
};

int main(int argc, const char *argv[])
{
    std::cout << "Creating B" << std::endl;
    B b1;
    std::cout << "Creating B by copy" << std::endl;
    B b2(b1);
    return 0;
}

Выход:

Creating B
A::Default constructor
B::Default constructor
Creating B by copy
A::Default constructor
B::Copy constructor

Мой вопрос: почему пользовательский конструктор копирования не вызывает конструктор копирования базового класса как поведение по умолчанию?

Ответы [ 3 ]

9 голосов
/ 07 февраля 2012

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

#include <iostream>

class A {
int a;
public:
A() {
    std::cout << "A::Default constructor" << std::endl;
}

A(const A& rhs) {
    std::cout << "A::Copy constructor" << std::endl;
}
};

class B : public A {
int b;
public:
B() {
    std::cout << "B::Default constructor" << std::endl;
}
B(const B& rhs):A(rhs) {
    std::cout << "B::Copy constructor" << std::endl;
}
};

int main(int argc, const char *argv[])
{
std::cout << "Creating B" << std::endl;
B b1;
std::cout << "Creating B by copy" << std::endl;
B b2(b1);
return 0;
}

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

Вывод:

Creating B
A::Default constructor
B::Default constructor
Creating B by copy
A::Copy constructor
B::Copy constructor
7 голосов
/ 07 февраля 2012

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

2 голосов
/ 07 февраля 2012

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

...