Проверка типа
Необходимость контроля типа при обращениях к виртуальным функциям может оказаться определенным ограничением для разработчиков библиотек. Например, хорошо бы предоставить пользователю класс "стек чего-угодно". Непосредственно в С++ это сделать нельзя. Однако, используя шаблоны типа и наследование, можно приблизиться к той эффективности и простоте проектирования и использования библиотек, которые свойственны языкам с динамическим контролем типов. К таким языкам относится, например, язык Smalltalk, на котором можно описать "стек чего-угодно". Рассмотрим определение стека с помощью шаблона типа:
template < class T > class stack { T * p; int sz; public: stack ( int ); ~stack ();
void push ( T ); T & pop (); };
Не ослабляя статического контроля типов, можно использовать такой стек для хранения указателей на объекты типа plane (самолет):
stack < plane * > cs ( 200 );
void f () { cs.push ( new Saab900 ); // Ошибка при трансляции : // требуется plane*, а передан car* cs.push ( new Saab37B ); // прекрасно: Saab 37B - на самом // деле самолет, т.е. типа plane cs.pop () -> takeoff (); cs.pop () -> takeoff (); }
Если статического контроля типов нет, приведенная выше ошибка обнаружится только при выполнении программы:
// пример динамическое контроля типа // вместо статического; это не С++ Stack s; // стек может хранить указатели на объекты // произвольного типа void f () { s.push ( new Saab900 ); s.push ( new Saab37B ); s.pop () -> takeoff (); // прекрасно: Saab 37B - самолет s.pop () -> takeoff (); // динамическая ошибка: // машина не может взлететь }
Для способа определения, допустима ли операция над объектом, обычно требуется больше дополнительных расходов, чем для механизма вызова виртуальных функций в С++.
Рассчитывая на статический контроль типов и вызов виртуальных функций, мы приходим к иному стилю программирования, чем надеясь только на динамический контроль типов. Класс в С++ задает строго определенный интерфейс для множества объектов этого и любого производного класса, тогда как в Smalltalk класс задает только минимально необходимое число операций, и пользователь вправе применять незаданные в классе операции. Иными словами, класс в С++ содержит точное описание операций, и пользователю гарантируется, что только эти операции транслятор сочтет допустимыми.