[проектирование C++] неявный виртуальный вызов в конструкторе
Внимание, вопрос, должны ли (и если да, то откуда)Капитан скажет, что должны и из документации, и, наверное, ошибется. Но мне больше интересно зачем нужно было вступление, если весь вопрос в последнем абзаце?
Капитан скажет, что должны и из документации, и, наверное, ошибется.а мне что-то кажется, что не ошибется. Это всегда очень заметный момент. Ну вот есть функция, у нее параметры, это документируется, понятно. Но всегда хочется осознавать, от чего еще зависит поведение функции. Ну там «при прочих равных», все дела. Ну вот это важный момент, что она использует функции, дописанные пользователем (тем, кто наследует). А уж то, что пускать подобные функции не стоит в конструкторе, должно быть в крови. Ну либо, обожжешься на этом, запомнишь, на некоторое время. Все равно от ошибок никто не застрахован
С другой стороны это что у нас? Шаблонный метод? Конструкция известная, значит должны быть известны и связанные проблемы. Надо вырабатывать эту ассоциацию и приравнивать клиентов шаблонных методов к самим виртуальным функциям.
Или даже проще: что стоит делать в конструкторе? За редким исключением всяких специальных объектов типа смарт-поинтеров или каких-нибудь переключателей внешнего состояния на время работы блока (например, контроллеров критической секции достаточно привести объект в корректное состояние, чтобы он был готов к дальнейшим действиям, в общем, минимум действий в конструкторе — это тоже логичное правило, прежде чем нарушать которое, в общем случае надо подумать.
getData все еще рекомендуется делать private
getData все еще рекомендуется делать privateчто значит "все еще"?
как это private? разве тогда его потомки смогут переопределить?
разве тогда его потомки смогут переопределить?конечно, метод ведь виртуальный
как это private? разве тогда его потомки смогут переопределить?зачем ты у меня это спрашиваешь? Ну вот если ты пишешь сюда, то у тебя, наверное, есть компилятор C++ под рукой. Ну возьми, проверь.
Саттер вообще настаивает на том, что все виртуальные методы должны быть private. С его доводами можно согласиться, но обычно ломает это делать.
А в этом случае автор явно пытается запрятать этот метод getData, ну так почему бы и от наследников его не спрятать?
ну я бы вообще сказал, что в конструкторе можно вызывать только final (приватные невиртуальные?) методы, которые ты сам определили. все остальное рано или поздно приведет к граблям ...
Вот, я понял, что мне не нравилось в этом коде. Зачем делать getData закрытым вообще? Все равно любой сможет сохранить объект в файл и прочитать строку оттуда. А что если кто-нибудь хочет сериализовать в строку? Это часто может пригодиться. Итого: просто оставить (пускай даже открытую) виртуальную функцию getData, а сохранять уже другим классом, который может сохранять в файл произвольную строчку
Секунду. Вроде плохо будет, если вызывать виртуальную функцию в конструкторе Base. А если в конструкторе производных классов, то все нормально сработает. Или нет?
Ну вдруг там несколько уровней наследования.
Ну автор треда этого, видимо, не подразумевал.
Ну хз, хз, автор треда — любитель пытаться предвидеть непредвидимое, это не первый его пост в подобном ключе
Вызывать можно. Только есть правило, что в момент исполнения конструктора таблица виртуальных функций ещё не работает, поэтому будет вызван совершенно определённый метод (статически связанный этого класса или выше по иерархии.
В деструкторах деструкторы классов наследников уже отработали, сами наследники разрушены, по этой причине связывание опять же статическое.
Значит, у меня пример дурацкий. Просто я подводил под мысль, что возможна ситуация ошибки, в которой никто не виноват. Такая возможность сильно омрачает мою веру прекрасное.
Если сделать дерево наследования их трех классов и вызвать printData в конструкторе среднего класса, то будет вызвана getData среднего класса. Интересный и понятный эффект.
Често говоря, первый раз слышу. Читал, что protected определяет интерфейс для потомков. Абстрактность говорит о необходимости (пере)определить.
Нет, если надо, то без вопросов, просто по умолчанию все же private.
Такая возможность сильно омрачает мою веру прекрасное.Речь все еще о C++?
Оставить комментарий
Realist
Есть правило, что нельзя вызывать виртуальную функцию в конструкторах и деструкторах. Или, по крайней мере, нужно полностью отдавать себе отчет в том, что ты делаешь.Положим, у меня есть базовый класс и неопределенная куча независимых потомков. Все они должны уметь некоторые, специфичные для класса, данные сохранять в файл и выводить на экран.
Вместо совсем простой иерархии
Я бы предпочел нечто
Таким образом я один раз пишу код для открытия файла / вывода на экран. Соответствующие функции невиртуальные, реализованы в базовом классе и используют виртуальную функцию получения строки с данными.
Возвращаемся к принципу не звать виртуальную функцию из конструктора. Положим, базовый класс пишет один программист, а потомков — другие, независимые. А файл реализации базового класса — только в бинарнике. Внимание, вопрос, должны ли (и если да, то откуда) авторы производных классов знать, что лучше не вызывать saveDataToFile и printData В конструкторе и деструкторе?
Спасибо