c++ quiz
Рассмотрим простую прогу с наследованием:
#include <stdio.h>
//
struct C {
C() {
printf ("- C::C()\n");
}
};
struct D : public C {
D(const C & o) : owner (o) {
printf (" `-D::D()\n");
}
private:
const C & owner;
};
//
int main() {
C c;
//
D d1(c);
D d2(d1);
//
return 0;
}Вопрос: что она выведет?
Чтобы окончательно вас сбить с толку рассмотрим объявленные и
используемые в программе конструкторы для D:
struct D : public C {
D(const C & o) {
// ....
}
// ...
}
//
int main() {
C c;
//
D d1(c); // [1]
D d2(d1); // [2]
// ...
}Итак, ответ:
$ g++ a.cc -o a && ./a
- C::C()
- C::C()
`-D::D()
# а конструктора для d2 и нет! :]
Как так?
А вот как:
- В
[1]используется конструкторD::D(const C &) - В
[2]используется конструктор копииD::D(const D &)(генерится компилятором)
Конструктор копии по умолчанию в нашем случае выглядит примерно так:
C::C(const C & c)
{}
D::D(const D & d) : C(d), owner (d.owner)
{}Часто это довольно гадкий и нежелательный эффект. В моём случае class С был низкоуровневым классом помощи посчета ссылок, для которого
конструктор копии по умолчанию делал полную ерунду и плодил утечки
памяти.
Реальный код, в котором я вчера нашел этот эффект не предполагал создания копии и должен был быть написан следующим образом:
//
int main() {
C c;
//
D d1(c);
D d2(static_cast<const C &>(d1)); // как для 'd1'
//
return 0;
}Чтобы впредь избежать проблем в дочерних классах, наследуемых от class С я просто спрятал конструкторы копии и присваивания:
#include <stdio.h>
//
struct C {
C() {
printf ("- C::C()\n");
}
private:
C(const C &); /* forbidden */
C & operator= (const C &); /* forbidden */
};В этом случае компилятор начнет ныть, что не может вызвать конструктор копии:
В функции «int main()»:
замечание: synthesized method «D::D(const D&)» first required here
Добавление этого кода позволило найти еще пару таких-же проблемных мест.