Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 211
Текст из файла (страница 211)
Это различие проистекает из соображения, что класс должен определять раскладку обьектов, а это лучше делать в одном месте. Кроме того, ив(лл-объявления и кт(лл-директивы применимы к классам весьма ограниченным образом (915.2.2). Пространства имен предпочтительнее классов, если все, что требуется — это инкапсуляция имен. В таком случае аппарат классов для проверки типов и создания обьектов не нужен; достаточно более простой концепции пространств имен. Приложение С.
Технические подробности 986 риЫ1с: ии риЫ; гоЫ т ( ); )' Здесь Х:: т < ) имеет неограниченный доступ: / о)г // о(г // об Члены производного класса имеют доступ к открытым и защищенным членам базового класса (9)5.3): с1алл л': риЫ)с Х ( юЫ телег(геь( ( ); юЫ У:: ин1ег(сед() рю =1; рю! = 2; риЫ=3; ) Глобальные функции могут обращаться только к открытым членам: "о(г11 < г*р) ( р->рпг = 1; // еггог: рггг - рггео!е р- >рю! = 2; // еп ог: рго! -рго<ес<е4, а 10 - не друг и не член Хили У р->риЫ = 3; //о(г; ) С.11.2. Доступ к базовым классам Как и члены класса, базовые классы также могут быть объявлены с ключевыми словами рпга!е, ргогесгег1 и риЫ1с: с1аел Х ( риб|с: (н! а; //...
)' сгалл И: рибас Х ( ); с!аел л'2: ргогесгей Х ( ); с!аел л3: рюаге Х ( ); Поскольку Хявляется открытым базовым классом для И, то любая функция может воспользоваться неявным преобразованием от И* к Х" там, где это нужно. Например: ЫХ:: <) рпг = 1; рюг= 2; риЫ =3 ) // егюп ргге - рг!гаге // обе рго! - рго<ес<ед и телег!чег(о есть функция-член нроитеодного класса // ОА С.11. Управление режимами доступа 98з коЫ !'(И* ру1, У2* ру2, УЗ* руЗ) ( Х* рх = ру1; Р оlс: Х - открытый базовый класс для И ру1->а = 7; //о/с рх = ру2; Р еггог: Х - защищенный базовьсй класс для )'2 ру2->а = 7; Реггог рх = руЗ; /У еггог: Х - закрытый базовый класс для УЗ руЗ->а = 7; //еггог ) Рассмотрим следующий фрагмент: с!авв У2с рюсесзед Х ( ); с!азз У2: риЫ!с У2 (гоЫУ(И*, У2*, УЗ*); ); Так как Х является защищенным базовым классом для У2, только члены и друзья класса У2 (а также члены и друзья классов, производных от л2, например Х2) могут воспользоваться неявным преобразованием от У2* к Х' там, где это нужно, как они могут получить доступ к открытым и защищенным членам класса Х Например: ру1, Уг*руг, УЗ* руз) ру2->а = 7; рх = руЗ; руЗ->а = 7; ) Наконец рассмотрим с1азз УЗс ригазеХ [гоЫГ(У!*, У2*, УЗ*); ); Поскольку Х является закрытым базовым классом для УЗ, только члены и друзья класса УЗ могут воспользоваться неявным преобразованием от УЗ* к Х" (где это нужно), как они могут обращаться к открытым и защищенным членам класса Х.
Например: юЫ УЗ с: У( И* ру1, У2* ру2, УЗ* руЗ) ( Х* рх = ру1; // о)а Х - открьстый базовый класс для И ру1->а = 7; //о/с рх = ру2г //еггог Х - защищенный базовый класс для )'2 ру2->а = 7; //еггог рх = руЗ; /У ой: Х - закрытый базовый класс для УЗ, /У и УЗ:.УО - член класса УЗ руЗ->а = 7; //ок юЫ 22 с: У( И* ( Х* рх = ру)с ру1->а = 7; рх = зйЫ; а= 7; рх = ру2; // о)с' Х - открытый базовый класс для У! /У о1с //о(с: Х- защищенный базовый класс для )2, а 22 наследует У2 У о)с // еггот Х - защищенный базовый класс для У2, а 22 наследует У2, // но мы не знаем, представляет ли ру2 объект 22, //или как У2..Х используется в не-22 объектак Р еггогс 22 не знает, как У2::а используется в не-22 объектак У ее ог: Х- закрытый базовый класс для УЗ У еггог Приложение С.
Технические подробности 988 С.11.3. Доступ ко вложенным классам Члены вложенного класса не имеют никаких специальных прав на доступ к членам объемлющего класса. Аналогично, члены объемлющего класса не имеют никаких особых прав на доступ к членам вложенного класса — всюду работают обычные правила доступа (5(0.2.2). Например: с1азз Оизег ( !урез(е! зпг Т! (пз з! риЫ(с: !пз 12; табе !пззз с!азз 1ппег ( (шх; Туз // еггот Оигегк Т - закрытый риЫ!с: гоЫ ((Оигег* р, тг г) 1пгя(Тппег* р) ! )! ком Оитег::1ппег:: ((Оигег* р, тг г) ( !7 >1е уг ,Р->12 = Р, ) //еггог: Оигегья - закрытый //о/с: Ои1ег:.'!2 - открытый !п! Оп<ее::е (1ппег* р) ( р->Т(1Ыз, 2); // ок; !ппегз~() - открытый ге!игп р->х; /еггог; !ппет;л - закрытый с1авз Оизег ( Зуреде!' тз Т! им 1; раб!!с: с1азз 1ппегг //предварителькое объявление класса Тг!еаза с1авз 1паегз с1азз Тп пег ( тг х! ту! //о)с' 1ппег - друг Часто, однако, бывает полезным предоставить членам вложенного класса неограниченный доступ к членам объемлющего класса.
Для этого достаточно объявить вложенный класс другом объемлющего класса. Например: С.12. Указатели на члены классов 989 риЫ!с: юЫ!'(Ои!ее' р, !п! и) )' )' юЫ Ои!ег:: 1ллег:: !'(Ои!ее* р, !и! н) ( р->! = кн Юое!ппег - друг С.11.4. Отношение «дружбы» Отношение дружбы не транзитивно и не наследуемо. Например: сглаз А ( /г!епй с1аее В; тга; ): с1аеа В 2г!епИ с1аеа С; ) с!аы С ( юЫу(А* р) ( р->аеег ) )' В еюол С - не друг А, а друг друга А с(ага О: риЫ(с В ( юЫу [А* р) ( р->аее; Вел ог: 1З - не друг А, а наследуев отн друга А ) )' С.12. Указатели на члены классов е!кис! С ( соле! сйае* на1; !п! 1г юЫрмл[[Ы[н) (сои! « га1 « н « 1п!Я(1п!); Естественно, что понятие указателя на члены класса (в)5.5) применяется как к членам данных, так и к функциям-членам, имеющим аргументы и возвращаемые значения.
Например: Приложение С. Технические подробности 990 иоЫ12 (); С(сопл( сваг* и) ( уа! = и' ) )' гуредегиоЫ (С:: *РМГЕ) (1пз); Ууказатель на функцию-член класса С с аргументом (п( гуреИеТ сопл( сйаг* С:: *РМ; 11 указатель на поле данных типа сопл сйагь класса С Тип указателя на функцию проверяется точно так же, как любой другой тип. С.1 3. Шаблоны Шаблон класса описывает, как можно сгенерировать класс по заданному подходящему набору аргументов шаблона.
Аналогично, шаблон функции описывает, как можно сгенерировать функцию по заданному подходящему набору аргументов шаблона. Таким образом, шаблоны используются для генерирования типов и исполнимого кода. Вместе с такой выразительной мощью возникают и некоторые сложности, связанные по большей части со множеством контекстов определения и использования шаблонов. С.1 3.1. Статические члены Шаблон класса может иметь статические члены.
Каждый класс, сгенерированный из шаблона, имеет свою собственную копию статических членов. Статические члены должны определяться отдельно и могут иметь специализации. Например: коЫ2'(Сь г1, Сь х2) ( С*р=а г; РМР1 р~= аС::рппг; РМрт = аС::иа1г х1.рппз(1); (х1. "рг) (2); х1. "Рт = "пк1"; р->"рт = "пи2"( х2.рг(п((З); (р->*РЛ (4); рТ= ьС::27; рТ= ьС::12; рт = ьС::1; рт = рг) гетр1азе<сЫт Т> с1ат Х ( г)' ... таис Т ь(еу иа1г вгагЫ Т* позе Х(Т а = ь(еТ га1) У епог: неправильный тип возврата ~У еггоп неправильный тип аргумента У еггог: несоответствие типа У еггог: несоответствие типа С.13. Шаблоны 991 !етр!а!е<с1аяя Т> ТХ<Г>: ."ИеТ га1; зу инициализируется Х<Т>О !етр1аге<с1аяя Т> Т* Х<Т>::пеп Х(Та) [l*... *!) !етр1аге<> 1и! Х<тг:: деТ яа1 = О; гетр!а!в<> тг* Х<т!>:: пее Х [тг 1) [ ! *... */ ) Если вы хотите сделать объект или функцию обшими для всех членов любого сгенерированного из шаблона класса, вы можете разместить их в нешаблонном базовом классе.
Например: затея В [ таис В* т!г д'оба[ай нулевой указатель для всех классов, производных от В )' (етр1аге<с1аяя Т> с1аяя Х: риЫ!с В [ 1... ): В* В::п11 = О; С.1 3.2. Друзья Шаблоны классов могут иметь друзей. Рассмотрим, например, Маозх и Уесгог из 911.5. В обшем случае они будут представляться шаблонами: гетр!аяе<с1аяя Т> с1аяя Маой; гетр!а!е<сгаяя Т> с!ат Уес1ог [ Тг[4); риЬИс: ТгГепд Уес!ог орега!ог* [сонэ! Маиы< Т> ь, сопи Уев!ось ) 11... )! гетр!иге<с!от Т> с1аяя Маягяк [ 1'есяог<Т> и [4); риЫ!с: уг1епд Уесяог< Т> орегаяог* [сопя! Магг!ха, сопт Уесяог< Т> я ) У...
)' Затем можно определить операцию умножения, имеюшую прямой доступ к данным из Магг[я и Уесгог.' !етр1аге<сгаяя Т> Уесгог<Т> орега!ог* [сопт Ма!ги<Т> ь т, сопя! Уесяог<Т>а г) [ У ... используем т.х(Ц и куЯ для прямого доступа к элементам Друзья не оказывают влияния на область видимости, в которой определен шаблонный класс; также они не влияют на область видимости, в которой этот шаблон 992 Приложение С. Технические подробности используется. Функции-друзья и операции-друзья находятся путем поиска, бази- рующегося на типе их аргументов (911.2.4, 911.5.1).
Как и функции-члены, функ- ции-друзья конкретизируются (ЭС.13.9.1) только, если осуществляется их вызов. С.13.3. Шаблоны в качестве параметров шаблонов Бывает полезным передать шаблон (а не класс или объект) в качестве аргумента шаблона. Например; гетр!аге<с1азз Т, гетр1аге<с1азз> сгазз С> сгазз Хгеу[г ( С<Т> пгетз; С<Т*> ге!в! )г Хгеггг<еппу, гесгог> х1 г Ь'хранит перекрестные ссьшки для Еппу в контейнере типа кесто Хгеф<1[есоггг, зег> х2; р хранит перекрестные ссьтки для 1[асану в контейнере типа зег Чтобы объявить шаблон как параметр шаблона, нужно указать требующиеся ему аргументы. Например, мы объявляем параметр С шаблона Хгеу1[ как шаблонный класс, которому требуется один аргумент-тип. Если мы этого не сделали бы, то не смогли бы использовать специализации С.