Delphi protected что это

Delphi protected что это

Опытный
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что этоDelphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Профиль
Группа: Участник
Сообщений: 557
Регистрация: 5.7.2008
Где: Прибалтика

Репутация: 1
Всего: 6

Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Опытный
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что этоDelphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50

Цитата(wikipedia)
TMyClass = class(TObject)
private
<Описанные в этой секции элементы не доступны извне (за пределами класса).>
<Здесь обычно находятся поля класса.>
protected
<Описанные в этой секции элементы доступны только классу и всем его потомкам.>
public
<Описанные в этой секции элементы доступны всем.>
published
<Описанные в этой секции элементы доступны всем и отображаются в Object Inspector'e.>
end;

Профиль
Группа: Админ
Сообщений: 3639
Регистрация: 31.7.2007
Где: Moscow, Dubai

Репутация: 50
Всего: 372

Это все секции класса.

Опытный
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что этоDelphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Профиль
Группа: Участник
Сообщений: 557
Регистрация: 5.7.2008
Где: Прибалтика

Репутация: 1
Всего: 6

Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Inspired =)
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что этоDelphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что этоDelphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 18
Всего: 191

public
Все члены класса, расположенные здесь, доступны из любой точки программы. Обычно здесь располагаются свойства и методы для использования класса непосредственно по назначению. Могут быть и абстрактные методы.

) помещаются в эту секцию.

protected
От private отличается тем, что члены класса доступны и любому из его потомков, даже если последний объявлен в другом модуле.
Обычно здесь методы в перспективе на модифицирование, чтобы менять поведение класса (часто виртуальные и динамические), а также готовые методы, которые мог бы использовать класс-потомок, дополняя свою внутреннюю реализацию. Также могут быть и абстрактные методы.

published
Область видимости как у секции public. Но, помимо прочего, эти свойства будут доступны в Инспекторе Объектов для изменения. При «авто-завершении» (auto-complete) класса средой Delphi все свойства и методы, которые были объявлены вне какой-либо секции, помещаются сюда.

automated
Редко используемая секция. Члены здесь разрешается размещать, если класс унаследован от класса TAutoObject, чтобы создавать сервера автоматизации. Область видимости как и у public. Эта секция имеет ограничения на дефиниции свойств и методов из-за направленности на технологию COM.

strict protected
Члены класса видны только классу и его потомкам.

Доступ к сгенерированной информации (п. 3 и 4) осуществялется через таблицу VMT (это по сути поле класса, но оно всегда скрыто, и всегда первое по счету) класса (по отрицательным смещениям).

Секции могут дублироваться по именам (их может дублировать и среда Delphi при «авто-завершении» класса).

Опытный
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что этоDelphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Профиль
Группа: Участник
Сообщений: 557
Регистрация: 5.7.2008
Где: Прибалтика

Репутация: 1
Всего: 6

Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Старательный
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Профиль
Группа: Участник
Сообщений: 223
Регистрация: 19.10.2006
Где: Молдова

Репутация: нет
Всего: 6

Можно еще кое-что уточнить по поводу «private, public, published, protected»?
Область видимости процедур (функций, переменных. ), находящихся в этих секциях, уже объяснили. То есть программист, в зависимости от своих задач, помещает объявление процедуры в нужную секцию. А как быть с процедурами, которые появляются в коде после, например, двойного щелчка по кнопке (procedure Button1Click(Sender: TObject);)? Их объявления автоматически появляются выше всех секций. Куда относятся эти процедуры, какая у них видимость?

Эксперт
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что этоDelphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что этоDelphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Профиль
Группа: Участник
Сообщений: 1108
Регистрация: 6.10.2006

Репутация: 10
Всего: 80

Цитата(Rrader @ 1.9.2008, 14:43 Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это)
1) Секция без названия у класса вашей формы, унаследованного по умолчанию от TForm, обслуживается Delphi. Но область её видимости не private, а published

Старательный
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Профиль
Группа: Участник
Сообщений: 223
Регистрация: 19.10.2006
Где: Молдова

Репутация: нет
Всего: 6

Старательный
Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

Профиль
Группа: Участник
Сообщений: 223
Регистрация: 19.10.2006
Где: Молдова

Репутация: нет
Всего: 6

Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это Delphi protected что это. Смотреть фото Delphi protected что это. Смотреть картинку Delphi protected что это. Картинка про Delphi protected что это. Фото Delphi protected что это

1. Публиковать ссылки на вскрытые компоненты

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

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »

[ Время генерации скрипта: 0.1307 ] [ Использовано запросов: 21 ] [ GZIP включён ]

Источник

Classes and Objects (Delphi)

This topic covers the following material:

Contents

Class Types

A class, or class type, defines a structure consisting of fields, methods, and properties. Instances of a class type are called objects. The fields, methods, and properties of a class are called its components or members.

Objects are dynamically allocated blocks of memory whose structure is determined by their class type. Each object has a unique copy of every field defined in the class, but all instances of a class share the same methods. Objects are created and destroyed by special methods called constructors and destructors.

A class type must be declared and given a name before it can be instantiated. (You cannot define a class type within a variable declaration.) Declare classes only in the outermost scope of a program or unit, not in a procedure or function declaration.

A class type declaration has the following form:

Required elements of the class type declaration

Optional elements of the class type declaration

Methods appear in a class declaration as function or procedure headings, with no body. Defining declarations for each method occur elsewhere in the program.

For example, here is the declaration of the TMemoryStream class from the Classes unit:

Given this declaration, you can create an instance of TMemoryStream as follows:

Inheritance and Scope

When you declare a class, you can specify its immediate ancestor. For example:

declares a class called TSomeControl that descends from Vcl.Controls.TControl. A class type automatically inherits all of the members from its immediate ancestor. Each class can declare new members and can redefine inherited ones, but a class cannot remove members defined in an ancestor. Hence TSomeControl contains all of the members defined in Vcl.Controls.TControl and in each of the Vcl.Controls.TControl ancestors.

The scope of a member’s identifier starts at the point where the member is declared, continues to the end of the class declaration, and extends over all descendants of the class and the blocks of all methods defined in the class and its descendants.

TObject and TClass

The System.TObject class, declared in the System unit, is the ultimate ancestor of all other classes. System.TObject defines only a handful of methods, including a basic constructor and destructor. In addition to System.TObject, the System unit declares the class reference type System.TClass:

If the declaration of a class type does not specify an ancestor, the class inherits directly from System.TObject. Thus:

The latter form is recommended for readability.

Compatibility of Class Types

A class type is assignment-compatible with its ancestors. Hence a variable of a class type can reference an instance of any descendant type. For example, given the declarations:

Object Types

The Delphi compiler allows an alternative syntax to class types. You can declare object types using the syntax:

where objectTypeName is any valid identifier, (ancestorObjectType) is optional, and memberList declares fields, methods, and properties. If (ancestorObjectType) is omitted, then the new type has no ancestor. Object types cannot have published members.

Since object types do not descend from System.TObject, they provide no built-in constructors, destructors, or other methods. You can create instances of an object type using the New procedure and destroy them with the Dispose procedure, or you can simply declare variables of an object type, just as you would with records.

Object types are supported for backward compatibility only. Their use is not recommended.

Visibility of Class Members

Every member of a class has an attribute called visibility, which is indicated by one of the reserved words private, protected, public, published, or automated. For example,

If a member’s declaration appears without its own visibility specifier, the member has the same visibility as the one that precedes it. Members at the beginning of a class declaration that do not have a specified visibility are by default published, provided the class is compiled in the <$M+>state or is derived from a class compiled in the <$M+>state; otherwise, such members are public.

For readability, it is best to organize a class declaration by visibility, placing all the private members together, followed by all the protected members, and so forth. This way each visibility reserved word appears at most once and marks the beginning of a new ‘section’ of the declaration. So a typical class declaration should be like this:

You can increase the visibility of a property in a descendent class by redeclaring it, but you cannot decrease its visibility. For example, a protected property can be made public in a descendant, but not private. Moreover, published properties cannot become public in a descendent class. For more information, see Property Overrides and Redeclarations.

Private, Protected, and Public Members

A private member is invisible outside of the unit or program where its class is declared. In other words, a private method cannot be called from another module, and a private field or property cannot be read or written to from another module. By placing related class declarations in the same module, you can give each class access to the private members of another class without making those members more widely accessible. For a member to be visible only inside its class, it needs to be declared strict private.

A protected member is visible anywhere in the module where its class is declared and from any descendent class, regardless of the module where the descendent class appears. A protected method can be called, and a protected field or property read or written to, from the definition of any method belonging to a class that descends from the one where the protected member is declared. Members that are intended for use only in the implementation of derived classes are usually protected.

A public member is visible wherever its class can be referenced.

Strict Visibility Specifiers

In addition to private and protected visibility specifiers, the Delphi compiler supports additional visibility settings with greater access constraints. These settings are strict private and strict protected visibility.

Class members with strict private visibility are accessible only within the class in which they are declared. They are not visible to procedures or functions declared within the same unit. Class members with strict protected visibility are visible within the class in which they are declared, and within any descendent class, regardless of where it is declared. Furthermore, when instance members (those declared without the class or class var keywords) are declared strict private or strict protected, they are inaccessible outside of the instance of a class in which they appear. An instance of a class cannot access strict private or strict protected instance members in other instances of the same class.

Published Members

Published members have the same visibility as public members. The difference is that run-time type information (RTTI) is generated for published members. RTTI allows an application to query the fields and properties of an object dynamically and to locate its methods. RTTI is used to access the values of properties when saving and loading form files, to display properties in the Object Inspector, and to associate specific methods (called event handlers) with specific properties (called events).

Published properties are restricted to certain data types. Ordinal, string, class, interface, variant, and method-pointer types can be published. So can set types, provided the upper and lower bounds of the base type have ordinal values from 0 through 31. (In other words, the set must fit in a byte, word, or double word.) Any real type except Real48 can be published. Properties of an array type (as distinct from array properties, discussed below) cannot be published.

Some properties, although publishable, are not fully supported by the streaming system. These include properties of record types, array properties of all publishable types, and properties of enumerated types that include anonymous values. If you publish a property of this kind, the Object Inspector will not display it correctly, nor will the property’s value be preserved when objects are streamed to disk.

All methods are publishable, but a class cannot publish two or more overloaded methods with the same name. Fields can be published only if they are of a class or interface type.

Automated Members (Win32 Only)

The following restrictions apply to methods and properties declared as automated.

The declaration of an automated method or property can include a dispid directive. Specifying an already used ID in a dispid directive causes an error.

On the Win32 platform, this directive must be followed by an integer constant that specifies an Automation dispatch ID for the member. Otherwise, the compiler automatically assigns the member a dispatch ID that is one larger than the largest dispatch ID used by any method or property in the class and its ancestors. For more information about Automation (on Win32 only), see Automation Objects.

Forward Declarations and Mutually Dependent Classes

If the declaration of a class type ends with the word class and a semicolon—that is, if it has the form

with no ancestor or class members listed after the word class, then it is a forward declaration. A forward declaration must be resolved by a defining declaration of the same class within the same type declaration section. In other words, between a forward declaration and its defining declaration, nothing can occur except other type declarations.

Forward declarations allow mutually dependent classes. For example:

Источник

Справочник функций и процедур Delphi: Protected

Protected
Деректива
Начинает раздел класса частных данных доступных подклассамunit

type Class declaration
Protected
Field | Property | Method declaration
<. >
end;

Описание
Директива Protected начинает раздел объявлений определения класса. В защищенном разделе, Поля(Fields), Свойства(Properties) и Методы(Methods) объявлены как доступные для этого класса и классов происходящих от этого. Но внешне не доступных пользователям класса.

Это подобно Private директиве, которая скрывает внутреннее выполнение класса, но не скрывает такие данные и методы от подклассов. Вообще, большинство данных и методов, внутренних для класса должны быть определены в разделе Protected. Часто это дает подклассам полезный доступ к ним. Только используйте Private, когда вы уверены, что хотите сохранить материал полностью локальным для текущего класса/модуля. Это может быть верным, когда подкласс хотел бы быть изолированным от родительских сложностей класса.

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

Похожие команды
Function Определяет подпрограмму, которая возвращает значение

Private Начинает частный (Private) раздел данных и методов в классе

Procedure Определяет подпрограмму, которая не возвращает значение

Property Определяет управляемый доступ к полям класса

Public Начинает внешне доступный раздел класса

Published Начинается изданный, внешне доступный раздел класса

Type Определяет новую категорию переменной или процесса

Источник

. when altering one’s mind becomes as easy as programming a computer, what does it mean to be human.

6 февраля 2013 г.

«Дружественность» в Delphi

Содержание

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

Инкапсуляция — один из четырёх важнейших механизмов объектно-ориентированного программирования, заключающийся в объединении данных с методами и скрытии реализации (т.н. «чёрный ящик» — доступность главного, сокрытие второстепенного). Инкапсуляцию применяют для обеспечения согласованности внутреннего состояния объекта. Применение инкапсуляции позволяет предельно локализовать изменения (при необходимости таких изменений), прогнозировать изменения (какие изменения в коде нужно сделать для заданного изменения функциональности) и прогнозировать последствия изменений.

Необходимость обхода инкапсуляции

Но объекты не существуют автономно, сами по себе. Поэтому на практике часто возникают ситуации, когда необходимо обеспечить более тесное взаимодействие объектов, не связанных иерархией. Это подразумевает, что один объект должен уметь обращаться к другому объекту в обход его публичного интерфейса. Простой пример: объект-коллекция и объект-элемент коллекции. Эти два класса, скорее всего, не будут наследоваться друг от друга, а будут двумя разными ветвями дерева наследования. Тем не менее, при добавлении элемента в коллекцию нужно установить владельца (для элемента), его индекс и другие данные для учёта. Само собой, подобный сервис не должен выставляться наружу, поскольку тогда сторонний код мог бы его менять и, таким образом, «испортить» данные объекта. Так что публичный интерфейс будет содержать методы типа «добавить элемент в коллекцию», но не «теперь этот объект — в той коллекции, а его индекс там — минус сто».

Разумеется, при добавлении элемента в коллекцию, необходимо внести элемент в список элементов ( FItems ) и назначить ему владельца ( FCollection ), поэтому этим двум классам необходимо иметь доступ к закрытым элементам друг друга в обход общего механизма разграничения доступа.

Понятие класса, дружественного другому классу

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

В Delphi нет специальных языковых конструкций для выделения дружественных классов. Вместо этого здесь используется иной механизм. А именно: любые классы в одном модуле (unit) автоматически считаются дружественными друг к другу и могут обращаться к закрытым элементам друг друга. Иными словами, расположение классов в одном модуле является необходимым и достаточным условием дружественности классов друг другу.

Поэтому в примере выше TCollection и TCollectionItem являются дружественными, поскольку расположены в одном модуле, так что допускается код типа такого: или такого:

Проблемы дружественности в Delphi

Таким образом, получается, что деление классов на дружественные друг другу заключается в распределении их (классов) по модулям (unit). Однако на практике критерий дружественности крайне редко выступает в качестве основного критерия для распределения классов. Чаще модуль объединяет логические связанные классы, цельные компоненты библиотеки и т.п. При этом может получаться, как много не связанных друг с другом (в плане дружественности) классов в одном модуле, так и дружественные классы, разнесённые по разным модулям (если такие классы принадлежат разным логическим компонентам).

Сужение дружественности: strict

Расширение дружественности: хак

Со второй проблемой (дружественные классы в разных модулях) несколько сложнее. В настоящее время Delphi не предоставляет никаких специальных языковых конструкций для разрешения этого конфликта. Вы не можете объявить классы дружественными друг другу, если они находятся в разных модулях. Поэтому программисту придётся использовать обходные пути.

Насколько безопасен такой хак? Ведь мы приводим объект одного класса ( TSomeClass ) к другому ( TDummySomeClass ), хотя он им не является. Ответ: достаточно безопасен. TDummySomeClass не содержит новых членов, мы не обращаемся к информации класса, мы используем только унаследованные элементы класса. Поэтому данное преобразование на уровне машинного кода — тождественно (т.е. вообще отсутствует). И никакие изменения в TSomeClass не приведут к поломке этого кода.

Расширение дружественности: интерфейсы

Итак, возвращаясь к нашим баранам, вариант второй разрешения конфликта — использование интерфейсов. Интерфейс (в смысле конструкции языка interface ) — это набор методов (читай: действий), которые можно произвести с объектом. Иными словами, это как бы «копия» public секции объекта. Вкусность тут в том, что их может быть много у одного объекта. Любой внешний код может запросить у объекта любой его сервис, если он знает его «имя» (в терминах интерфейсов: имя = GUID).

Таким образом, класс TSomeClass может реализовывать один или несколько интерфейсов, предназначенных для его дружественных классов, расположенных в других модулях. Чтобы подчеркнуть внутреннюю направленность интерфейсов, их можно вынести в отдельный недокументированный модуль. Тогда TAnotherClass может запросить у объекта класса TSomeClass интерфейс для внутренних манипуляций:
Как видите, вариант с интерфейсами — это гарантировано чистый путь, но неприятен он именно необходимостью смешивать объекты и интерфейсы (т.е. сущности с разным принципом управления временем жизни) в рамках одного класса. Как правило, чистота этого подхода не перевешивает его сложности по сравнению с чистым хаком, описанным выше.

Множественное наследование и интерфейсы

Насколько я понимаю, для решения этой проблемы (в том числе) в других языках программирования вводится поддержка множественного наследования: один класс может удовлетворять сразу нескольким функциональностям. К примеру, студент может быть не только человеком, но и рабочим, и музыкантом, и членом семьи (т.е. наследоваться от них в терминах множественного наследования). При этом, если наследуемые классы, в свою очередь, также наследуются друг от друга в различных комбинациях, то могут возникать конфликты (например, если «музыкант» и «член семьи» наследуют «прозвище» от «человек» с замещением реализации, то какую из реализаций должен брать «студент»?). Само собой, языки с поддержкой множественного наследования также содержат механизмы разрешения таких конфликтов. В целом же, множественное наследование часто критикуется. Проблемы, его чрезмерная сложность приводят критиков к выводу, что от него больше вреда, чем пользы. При этом также звучит мнение, что множественное наследование (как расширение «простого» одиночного наследования) — ошибочная концепция, порождённая неверным анализом и проектированием.

В Delphi проблемы множественного наследования решаются интерфейсами. Интерфейс — это полностью абстрактный класс, все методы которого виртуальны и абстрактны. Иными словами, говоря грубо, интерфейс — это запись ( record ) с указателями на функции. Каждый метод интерфейса должен быть реализован в классе. Причём реализацию вы либо пишете сами, либо наследуете, либо делегируете (для случая агрегации). Иными словами, любой интерфейс реализуется классом без конфликтов. Плюс, в каждый момент времени вы работаете с одним конкретным интерфейсом, а не с «объединённым набором интерфейсов», поэтому проблемы выбора нужной реализации тут просто нет — будет использоваться метод используемого интерфейса. Не та реализация? Берём другой (нужный) интерфейс с нужной реализацией.

Также замечу, что в Delphi отсутствует возможность множественного наследования не только классов, но и интерфейсов (множественное наследование интерфейсов существенно проще множественного наследования классов, поскольку интерфейсы не содержат реализации; тем не менее, даже здесь есть одна возможность для конфликтов).

В целом же, я считаю, что использование интерфейсов — это наиболее правильный вариант реализации множественного наследования, поскольку явное указание реализации исключает конфликты. Введение понятия интерфейсов является компромиссом, позволяющим получить преимущества множественного наследования, не реализуя его в полном объёме и, таким образом, не сталкиваясь со специфичными для него сложностями. Именно такой подход принят во многих современных языках — не только в Delphi, но и, к примеру, C# или Java.

Вы всё ещё используете объекты? Тогда мы идём к вам

Я уже кратко выразил основную мысль выше: объекты удобны для реализации функциональности (наследование/полиморфизм), но неудобны для использования. Добавлю только, что, помимо уже упомянутых ограничений, объекты неудобны ручным слежением за временем жизни. Интерфейсы же относятся к типам с автоматическим управлением временем жизни, что существенно упрощает разработку кода. Кроме того, интерфейсы — языко-независимы (т.е. ими можно обмениваться между кодом, написанных на разных языках), в отличие от классов, реализация которых своя в каждом языке программирования.

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

Иными словами, у интерфейсов есть куча плюсов, но есть и некоторые минусы. Во-первых, использование интерфейсов подвержено проблеме циклических ссылок (которую, впрочем можно легко обойти, следуя нескольким простым правилам разработки). Во-вторых, большая часть кода VCL и RTL написана в те времена, когда никакой поддержки интерфейсов в Delphi не было (историческая справка: изначально интерфейсы были введены в Delphi для поддержки технологии COM, но впоследствии их стали использовать более широко). Соответственно, весь этот код написан на объектах. И он наследуется и в современные версии Delphi. Более того, такой подход используют и сторонние библиотеки, руководствуясь «ну раз так поступает сам разработчик среды, то и мы тоже будем так делать». Итого, у вас может быть проблема состыковки кода с ручным и автоматическим управлением временем жизни. К сожалению, обычные интерфейсы в Delphi нельзя сделать «чистыми» (т.е. без обвеса автоматического управления). Вы можете добиться этого обходным путём, но это неудобно без поддержки со стороны языка.

Некоторые считают, что уже упомянутые плюсы интерфейсов не перевешивают их минусы. Возможно это и так. Но у интерфейсов есть одно существенное свойство, к которому я подвожу: интерфейс позволяет описывать некоторые желательные свойства, которыми могут обладать сущности. Интерфейс, по сути, является не только синтаксической, но и семантической конструкцией, используемой для спецификации услуг, предоставляемых компонентом. Интерфейс определяет границу взаимодействия между компонентами, определяя определённую абстракцию, которую осуществляет реализующая сторона. Интерфейс — это «договор», который обязуется выполнить компонент.

К чему это я? Когда мы говорим про ООП — мы говорим в первую очередь про наследование. Это именно то свойство (из наследования, абстракции, инкапсуляции и полиморфизма), которое наиболее ярко определяет ООП. Когда нас учат ООП, нас учат моделировать мир иерархиями объектов: объекты в программе отражают сущности реального мира. Но в реальном мире не существует понятия наследования (кроме нескольких узких областей). В реальной жизни стул не является наследником мебели. И уж тем более студент не является множественным наследником «человек», «рабочий», «музыкант».

Я не говорю, что наследование — это зло. Это удобная концепция, лучше всего раскрывающаяся для повторного использования кода (если у вас есть класс, вы можете наследоваться от него, чтобы сохранить его функциональность и внести некоторые изменения). Впрочем, при необходимости в качестве альтернативы наследованию можно выбрать агрегацию/делегирование.

Проблема в том, что унаследовавшись от одного предка, класс уже не может наследоваться от других. Изменение предка становится опасным. Зачастую правильное использование private и protected требует от программиста неслабых телепатических способностей: что может понадобится нашим наследникам, а что нет?

Иными словами, использование объектов мешает вам выражать понятия на языке реального мира. Дерево наследования становится не помощником, а ограничивающим фактором. Вам придётся создавать промежуточные объекты, единственное назначение которых будет состоять в преодолении этих ограничений (объекты-адаптеры, агрегирующие объекты и т.п.).

Если же вместо объектов вы будете оперировать интерфейсами, то ваш код будет более приближен к реальному миру. У вас может быть «студент», и он не будет наследоваться от «человека», но он будет иметь имя, т.к. студент одновременно является и «человеком». И если кому-то нужен «студент», то ему совершенно не обязательно наследоваться от «человека», «млекопитающего» или ещё более низкого класса, если его всего-лишь интересуют университет, курс и группа «студента». Конечно, вы можете и должны использовать объекты и наследование при реализации интерфейсов: в конце концов, наследование — удобный способ повторного использования кода. Иными словами, суммируя мысль: объекты — язык описания реализации, интерфейсы — язык описания реального мира.

Бонус: секция published

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *