Язык программирования C++ для профессионалов



           

Обширный интерфейс - часть 2


class slist_container : public container, private slist { public: void put(const T*); T* get();

T*& operator[](int) { throw Bad_operation("slist::[](int)"); } T*& operator[](const* char) { throw Bad_operation("slist::[](char*)"); } // ... };

Чтобы упростить обработку динамических ошибок для списка введены операции индексирования. Можно было не вводить эти нереализованные для списка операции и ограничиться менее полной информацией, которую предоставляют особые ситуации, запущенные в классе container:

class vector_container : public container, private vector { public: T*& operator[](int); T*& operator[](const char*); // ... };

Если быть осторожным, то все работает нормально:

void f() { slist_container sc; vector_container vc; // ... }

void user(container& c1, container& c2) { T* p1 = c1.get(); T* p2 = c2[3]; // нельзя использовать c2.get() или c1[3] // ... }

Все же для избежания ошибок при выполнении программы часто приходится использовать динамическую информацию о типе (§13.5) или особые ситуации (§9). Приведем пример:

void user2(container& c1, container& c2) /* обнаружение ошибки просто, восстановление - трудная задача */ { try { T* p1 = c1.get(); T* p2 = c2[3]; // ... } catch(container::Bad_operation& bad) { // Приехали! // А что теперь делать? } }

или другой пример:

void user3(container& c1, container& c2) /* обнаружение ошибки непросто, а восстановление по прежнему трудная задача */ { slist* sl = ptr_cast(slist_container,&c1); vector* v = ptr_cast(vector_container, &c2);

if (sl && v) { T* p1 = c1.get(); T* p2 = c2[3]; // ... } else { // Приехали! // А что теперь делать? } }

Оба способа обнаружения ошибки, показанные на этих примерах, приводят к программе с "раздутым" кодом и низкой скоростью выполнения. Поэтому обычно просто игнорируют возможные ошибки в надежде, что пользователь на них не натолкнется. Но задача от этого не упрощается, ведь полное тестирование затруднительно и требует многих усилий.

Поэтому, если целью является программа с хорошими характеристиками, или требуются высокие гарантии корректности программы, или, вообще, есть хорошая альтернатива, лучше не использовать обширные интерфейсы. Кроме того, использование обширного интерфейса нарушает взаимнооднозначное соответствие между классами и понятиями, и тогда начинают вводить новые производные классы просто для удобства реализации.




Содержание  Назад  Вперед