Бьерн Страуструп. Язык программирования С++


Множественное наследование



бет11/124
Дата16.07.2016
өлшемі3.27 Mb.
#204081
түріКнига
1   ...   7   8   9   10   11   12   13   14   ...   124

1.5.3 Множественное наследование


Если класс A является базовым классом для B, то B наследует атрибуты

A. т.е. B содержит A плюс еще что-то. С учетом этого становится очевидно,

что хорошо, когда класс B может наследовать из двух базовых классов A1 и

A2. Это называется множественным наследованием.
Приведем некий типичный пример множественного наследования. Пусть есть

два библиотечных класса displayed и task. Первый представляет задачи,

информация о которых может выдаваться на экран с помощью некоторого

монитора, а второй - задачи, выполняемые под управлением некоторого

диспетчера. Программист может создавать собственные классы, например,

такие:
class my_displayed_task: public displayed, public task

{

// текст пользователя



};
class my_task: public task {

// эта задача не изображается

// на экране, т.к. не содержит класс displayed

// текст пользователя

};
class my_displayed: public displayed

{

// а это не задача



// т.к. не содержит класс task

// текст пользователя

};
Если наследоваться может только один класс, то пользователю доступны

только два из трех приведенных классов. В результате либо получается

дублирование частей программы, либо теряется гибкость, а, как правило,

происходит и то, и другое. Приведенный пример проходит в С++ безо всяких

дополнительных расходов времени и памяти по сравнению с программами, в

которых наследуется не более одного класса. Статический контроль типов от

этого тоже не страдает.
Все неоднозначности выявляются на стадии трансляции:
class task

{

public:



void trace ();

// ...


};
class displayed

{

public:



void trace ();

// ...


};
class my_displayed_task:public displayed, public task

{

// в этом классе trace () не определяется



};
void g ( my_displayed_task * p )

{

p -> trace (); // ошибка: неоднозначность



}
В этом примере видны отличия С++ от объектно-ориентированных диалектов

языка Лисп, в которых есть множественное наследование. В этих диалектах

неоднозначность разрешается так: или считается существенным порядок

описания, или считаются идентичными объекты с одним и тем же именем в

разных базовых классах, или используются комбинированные способы, когда

совпадение объектов доля базовых классов сочетается с более сложным

способом для производных классов. В С++ неоднозначность, как правило,

разрешается введением еще одной функции:


class my_displayed_task:public displayed, public task

{

// ...



public:

void trace ()

{

// текст пользователя



displayed::trace (); // вызов trace () из displayed

task::trace (); // вызов trace () из task

}

// ...


};
void g ( my_displayed_task * p )

{

p -> trace (); // теперь нормально



}


1.5.4 Инкапсуляция


Пусть члену класса (неважно функции-члену или члену, представляющему

данные) требуется защита от "несанкционированного доступа". Как разумно

ограничить множество функций, которым такой член будет доступен? Очевидный

ответ для языков, поддерживающих объектно-ориентированное

программирование, таков: доступ имеют все операции, которые определены для

этого объекта, иными словами, все функции-члены. Например:
class window

{

// ...



protected:

Rectangle inside;

// ...

};
class dumb_terminal : public window



{

// ...


public:

void prompt ();

// ...

};
Здесь в базовом классе window член inside типа Rectangle описывается



как защищенный (protected), но функции-члены производных классов,

например, dumb_terminal::prompt(), могут обратиться к нему и выяснить, с

какого вида окном они работают. Для всех других функций член

window::inside недоступен.


В таком подходе сочетается высокая степень защищенности

(действительно, вряд ли вы "случайно" определите производный класс) с

гибкостью, необходимой для программ, которые создают классы и используют

их иерархию (действительно, "для себя" всегда можно в производных классах

предусмотреть доступ к защищенным членам).
Неочевидное следствие из этого: нельзя составить полный и

окончательный список всех функций, которым будет доступен защищенный член,

поскольку всегда можно добавить еще одну, определив ее как функцию-член в

новом производном классе. Для метода абстракции данных такой подход часто

бывает мало приемлемым. Если язык ориентируется на метод абстракции

данных, то очевидное для него решение - это требование указывать в

описании класса список всех функций, которым нужен доступ к члену. В С++

для этой цели используется описание частных (private) членов. Оно

использовалось и в приводившихся описаниях классов complex и shape.
Важность инкапсуляции, т.е. заключения членов в защитную оболочку,

резко возрастает с ростом размеров программы и увеличивающимся разбросом

областей приложения. В $$6.6 более подробно обсуждаются возможности языка

по инкапсуляции.




1.6 Пределы совершенства


Язык С++ проектировался как "лучший С", поддерживающий абстракцию

данных и объектно-ориентированное программирование. При этом он должен

быть пригодным для большинства основных задач системного программирования.


Основная трудность для языка, который создавался в расчете на методы

упрятывания данных, абстракции данных и объектно-ориентированного

программирования, в том, что для того, чтобы быть языком общего

назначения, он должен:


- идти на традиционных машинах;
- сосуществовать с традиционными операционными системами и языками;
- соперничать с традиционными языками программирования в эффективности

выполнения программы;


- быть пригодным во всех основных областях приложения.
Это значит, что должны быть возможности для эффективных числовых

операций (арифметика с плавающей точкой без особых накладных расходов,

иначе пользователь предпочтет Фортран) и средства такого доступа к памяти,

который позволит писать на этом языке драйверы устройств. Кроме того, надо

уметь писать вызовы функций в достаточно непривычной записи, принятой для

обращений в традиционных операционных системах. Наконец, должна быть

возможность из языка, поддерживающего объектно-ориентированное

программирование, вызывать функции, написанные на других языках, а из

других языков вызывать функцию на этом языке, поддерживающем

объектно-ориентированное программирование.


Далее, нельзя рассчитывать на широкое использование искомого языка

программирования как языка общего назначения, если реализация его целиком

полагается на возможности, которые отсутствуют в машинах с традиционной

архитектурой.


Если не вводить в язык возможности низкого уровня, то придется для

основных задач большинства областей приложения использовать некоторые

языки низкого уровня, например С или ассемблер. Но С++ проектировался с

расчетом, что в нем можно сделать все, что допустимо на С, причем без

увеличения времени выполнения. Вообще, С++ проектировался, исходя из

принципа, что не должно возникать никаких дополнительных затрат времени и

памяти, если только этого явно не пожелает сам программист.
Язык проектировался в расчете на современные методы трансляции,

которые обеспечивают проверку согласованности программы, ее эффективность

и компактность представления. Основным средством борьбы со сложностью

программ видится, прежде всего, строгий контроль типов и инкапсуляция.

Особенно это касается больших программ, создаваемых многими людьми.

Пользователь может не являться одним из создателей таких программ, и может

вообще не быть программистом. Поскольку никакую настоящую программу

нельзя написать без поддержки библиотек, создаваемых другими

программистами, последнее замечание можно отнести практически ко всем

программам.


С++ проектировался для поддержки того принципа, что всякая программа

есть модель некоторых существующих в реальности понятий, а класс является

конкретным представлением понятия, взятого из области приложения ($$12.2).

Поэтому классы пронизывают всю программу на С++, и налагаются жесткие

требования на гибкость понятия класса, компактность объектов класса и

эффективность их использования. Если работать с классами будет неудобно

или слишком накладно, то они просто не будут использоваться, и программы

выродятся в программы на "лучшем С". Значит пользователь не сумеет

насладиться теми возможностями, ради которых, собственно, и создавался

язык.





Достарыңызбен бөлісу:
1   ...   7   8   9   10   11   12   13   14   ...   124




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет