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