2012-02-07 4 views
31

Рассмотрим иерархию классов, где 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 

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

+2

Если бы это было так по умолчанию, как бы вы указали случай, когда вы не хотите, чтобы это произошло? – PlasmaHH

+0

@PlasmaHH 'ParentClass()' в списке инициализаторов. По-моему, это все равно было бы непоследовательным и запутанным. –

+0

@MarkB: Действительно, я надеялся, что он придет к такому же выводу, подумав об этом ... – PlasmaHH

ответ

7

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

1

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

8

Все базовые дочерние конструкторы называют родительский конструктор по умолчанию. Так определяется стандарт. Как вы отметили, если вы хотите, базовый класс 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):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; 
} 

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

+5

'Все базовые дочерние конструкторы называют родительский конструктор по умолчанию.' ... за исключением неявного конструктора копирования :)! –

+0

Неявный конструктор копирования - это явное имя для наиболее примитивной операции, предоставляемой компилятором, побитовая копия источника в пункт назначения. ИМО - просто причудливое имя. – shakthi

Смежные вопросы