Правила программирования на Си и Си++

       

Проектируйте с учетом наследования


Никогда не надейтесь, что класс не будет использоваться в качестве базового класса. Сосредоточимся на случае с примером управляющего элемента-редактора из предыдущего правила. Я бы хотел реализовать такой элемент, наследуя одновременно от класса 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 со страницы 155 является виртуальной, то я могу сделать следующее:

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

буфер обновляется, но также модифицируется заголовок его окна.



Содержание раздела