Правила программирования на С и С++. Главы 7-8 - Проектируйте с учетом наследования
ОГЛАВЛЕНИЕ
112. Проектируйте с учетом наследования.
Никогда не надейтесь, что класс не будет использоваться в качестве базового класса. Сосредоточимся на случае с примером управляющего элемента-редактора из предыдущего правила. Я бы хотел реализовать такой элемент, наследуя одновременно от класса window и от класса string, потому что он обладает свойствами обоих. У меня ничего бы не получилось, если бы многие из функций string не были виртуальными. То есть, так как я могу делать со строкой следующее:
string str = "xxx"; // инициализировать строку значением "xxx"str = "Абв"; // заменить предыдущее значение на "Абв"
str += "где"; // присоединяет "где" к имеющейся строке.
то хотел иметь возможность делать следующее, чтобы поместить текст как в буфер, принадлежащий управляющему элементу-редактору, так и в соответствующее окно: class edit_control : public string , public window{/* ... */}edit_control edit = "xxx";
edit = "Абв";
edit += "где";
Я бы также хотел передавать свой объект edit_control в функцию, ожидающую в качестве аргумента string, так чтобы любые изменения, которые эта функция делает в (том, что она принимает за) string, автоматически отображались и в окне управляющего элемента-редактора.
Все это не возможно, если функции, подобные operator=() и operator+=(), не виртуальные в классе string и тем самым, не позволяющие мне тем самым менять их поведение в производном классе edit_control. Например, так как функция operator=() класса string из листинга 7 со страницы 111 является виртуальной, то я могу сделать следующее:
class edit_control : public string , public window{ // ...virtual string ?operator=( const string ?r );
}virtual string ?edit_control::operator=( const string ?r )
{
*(string *)this = r;window::caption() = r; // операция разрешения видимости window:: просто для
// ясности}Следующей функции может быть передан или простой объект string, или объект edit_control; она не знает или ей все равно, какой конкретно: f( string *s ){
// ...*s = "Новое значение" ;
}В случае объекта string внутренний буфер обновляется. В случае edit_control буфер обновляется, но также модифицируется заголовок его окна.