Записи по ЯП, страница 5
Описание файла
Документ из архива "Записи по ЯП", который расположен в категории "". Всё это находится в предмете "языки программирования" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Онлайн просмотр документа "Записи по ЯП"
Текст 5 страницы из документа "Записи по ЯП"
public разрешает доступ всем
private разрешает доступ только «своему»
protected разрешает доступ «своим» и «своему»
class X
{
….
protected: void f();
……
};
class Z:public X
{
….
…..
};
class Y:public X
{
void g()
{
f(); //так можно
Y another;
another.f(); // так тоже можно
Z getanother;
getanother.f(); // В C# и Java так нельзя (у класса Y и класса Z независимые контракты // с классом X). В C++ так можно
(X)getanother.f(); // В C# и Java так будет работать (в C++ и подавно)
};
Перегрузка операций
a += b;// ~a.operator+=(b)
a + b;
Есть два пути вычисления этого выражения:
a.operator+(b); или
operator+(a,b);
class X
{
public:
X operator+(X & a);
X(T);
};
//либо
X operator +(X & a, X & b);
T t;
X a,b;
a = a + b;
a = t + b; // ищет T.operator+(X), operator+(T,X) и т.д.
Правильным является operator+(X(T),T)
Если требуется, чтобы доступ к приватным членам был не только у «своего», можно для этой этого объявить нужную дружественную конструкцию в теле класса:
friend «объявление друга»;// Можно писать сразу определение. Другом может быть функция или целый класс
friend «прототип глобальной функции»
friend «прототип функции-члена другого класса»
friend class «имя класса-друга»;// Все методы этого класса становятся дружественными
В Delphi, C#, Java друзей нет
В них реализованы этот механизм реализован немного по-другому:
Delphi UNIT
Java package
C# assembly
В Java по умолчанию пакетный доступ. Это значит, что использовать класс может каждый класс из этого пакета. Если класс объявить как «public class …», то он будет доступен и вне пакета. Использовать класс – наследовать, создавать объекты.
C#:
Сборка – надъязыковое понятие в .NerFramework. Сборка представляет собой совокупность файлов + манифест сборки, Любая сборка, статическая или динамическая, содержит коллекцию данных с описанием того, как ее элементы связаны друг с другом. Эти метаданные содержатся в манифесте сборки. Манифест сборки содержит все метаданные, необходимые для задания требований сборки к версиям и удостоверения безопасности, а также все метаданные, необходимые для определения области действия сборки и разрешения ссылок на ресурсы и классы.
Внутри сборки идёт разделение на пространства имён, которые содержат описания классов.
Для использования какого-либо пространства имён нужно сначала подключить сборку, содержащую его. Пространство имён может быть «размазана» по нескольким сборкам.
В C# для членов классов имеются следующие квалификаторы доступа:
-
public
-
private // по умолчанию
-
protected
-
internal – член доступен только в классах из сборки
-
internal protected – член доступен только в классах-наследниках, находящихся в сборке
Для самих классов:
-
public – класс можно использовать в любых классах
-
internal – класс можно использовать только в классах из его сборки (по умолчанию)
public class X //Этот класс может унаследовать любой класс
{
….
internal int a; // Это переменная доступна только внутри сборки
….
}
internal class Y //Этот класс может унаследовать только класс из сборки
{
….
}
Delphi
type T = class
…. // здесь объявляются члены, видимые везде их данного модуля и не видимые
// других
public
….
protected
….
private
…..
end;
UNIT – единица дистрибуции
Специальные функции
Функции-члены, обладающие семантикой обычных функций-членов, о которых компилятор имеет дополнительную информацию.
Конструктор – порождение, инициализация
Деструктор – уничтожение (В Java и C# не деструкторов, вместо это можно сделать собственный метод Destroy() )
Управление жизненным циклом объекта
-
создание, инициализация
-
использование
-
уничтожение
У конструктора нет возвращаемого значения.
Т.к. все объекты в C# и Java и Delphi размещаются в динамической памяти, то в этих языках обязательна операция явного размещения объектов:
X = new X(); // В Си++ X * a = new X;
Синтаксис конструкторов и деструкторов:
C++. C#, Java, D
class X
{
X(«параметры»);// В С# и Java обязательно определение тела
}
Delphi
type X = class
constructor Create; // Имя конструктора произвольное
destructor Destroy; // имя деструктора произвольное
end;
…..
a:X;
….
a := X.Create;
В C++, C#, Java конструкторы не наследуются, но могут автоматически генерироваться компилятором по определённым правилам.
Классификация конструкторов:
-
Конструктор умолчания X();
-
Конструктор копирования X(X &); X(const X & );
-
Конструктор преобразования X(T); X(T &); X(const T &);
В классах из простанства имён System платформы .NetFramework не определены конструкторы копирования. Вместо этого, если это предусмотрено проектировщиками, имеется метод clone();
Абстрактные классы и интерфейсы
Сами по себе иерархии классов бесполезны, если в них нету динамически связанных методов.
-
Если существуют признаки, общие для всех объектов в класса иерархии, то эти признаки целесообразно поместить в базовый класс
-
У каждого объекта класса имеется состояние (текущие значения параметров) и поведение (методы класса)
-
Некоторая функциональность (особенности поведения), общая для всех классов в иерархии, может быть реализована только при дальнейшей детализации в производных классах.
=> приходим к понятию абстрактного базового класса
В языках Delphi, Оберон-2, TP 5.5, C++, Java, C# имеется языковая поддержка абстрактных классов.
Пример:
Figure – абстрактная фигура
Общие данные – (x,y) – координаты фигуры
Общие методы – Draw(), Move() – не могут быть реализованы для абстрактной фигуры
Что будет если просто не определить витуальную функцию в базовом классе:
Полиморфный класс – класс, в котором есть виртуальные функции (и. следовательно, таблица виртуальных функций)
class X
{
public:
virtual void f(); //Объявлена, но не определена
void g();//Объявлена, но не определена
}
class Y: public X
{
public
virtual void f() {…;}//Замещена
}
….
X * py = new Y(); // уже здесь компилятор выдаст ошибку из-за того, т.к. непонятно что записывать в таблицу виртуальных функций
py -> f();
X a; // здесь компилятор также выдаст ошибку из-за того, из-за того, что не сможет заполнить таблицу виртуальных функций. Если бы функция X:: f() не была виртуальной, то ошибки здесь не было бы.
a.g();// ошибка, т.к X::g() не определена
Решение проблемы – языковая поддержка
В C#, Java:
abstract перед классом и перед функцией, для которой не существует реализации на данном уровне детализации. Такие функции и классы, их содержащие, называют аббстрактными
abstract class Figure //Абстрактный класс
{
abstract public void Draw(); // Функция без реализации
abstract public void Move();// Функция без реализации
}
В C++:
Чисто виртуальная функция (абстрактная) – virtual «прототип» = 0;
В Аде:
procedure P( X : T ) is abstract;
где T – тегированный тип.
Объекты абстрактных классов нельзя создавать.
При вызове виртуальной функции в конструкторе виртуальность вызова снимается:
сlass X{…}
class Y: public X{…}
class Z: public Y {…}
При создании объекта класса Z сначала вызовется конструктор класса X, потом класса Y и в самом конце класса Z. Нельзя вызвать в конструкторе класса Y замещённую функцию из Z, потому что объект Z ещё не до конца создан и для него ещё даже нет таблицы виртуальных функций.
Существует метод, который не должен быть чисто виртуальным – деструктор. Он всегда должен быть виртуальным и реализованным.
Base * px = new Derived;
«использование»
delete(px); // уничтожиться должен объект класса Derived
Различие между абстрактными классами и абстрактными типами данных:
В абстрактных классах абстрагируются от реализаций некоторых методов. В абстрактных типах данных абстрагируются от всей структуры.
Например множество – каждое множество должно поддерживать операции
-
include(const T &)
-
exclude( const T &)
При этом, естественно, реализация этих методов зависит от типа элементов, способа хранения и т.д.
class Iset
{
virtual void include(const T &) = 0;
virtual exclude(const T &) = 0;
«статические члены»
}
Такой класс называется класс-интерфейс. В таких классах не имеет смысл объявлять нестатические поля, т.к. не реализовано ни одного методы для работы с ними.
class Slist{…}
class Slist_Set: public Iset, private Slist {…; } // Iset – интерфейс
Iset * Move()
{
….
return new Slist_set(«параметры»);
}
В C# и Java, в отличие от C++, существует языкового понятия интерфейса:
interface «имя»
{
«объявления членов»
}
Внутри интерфейса могут быть статические поля. Поля без «static» будут восприняты как статические. Также членами интерфейса могут быть методы и свойства, которые считаются чисто виртуальными и публичными. Т.е. интерфейс – чистый контракт, не реализующий структуру.
Если класс наследует интерфейс и не определяет все методы интерфейса, то он становится абстрактным.
Множественное наследование
Только в C++ поддерживается множественное наследование. В C# и Java множественное наследование поддерживается только для интерфейсов.
C#: class D: [«класс»]{, «интерфейс»}
Java: class D extends Base implements «интерфейс» {, «интерфейс»}
Проблемы, связанные с множественным наследованием:
-
Конфликт имён
Java:
interface Icard
{
void Draw(){ …; }// Раздать карты
}
interface IGUIControl
{
{
void Draw(){ …; } //нарисовать колоду
}
class Sample implements ICard, IGUIControl {…; }// Ошибка!!
C++
class D public I1, public I2
{
virtual void I1::f(){…;} // Операция разрешения видимости
virtual void I2::f(){…;} // Операция разрешения видимости
}
…
D * px = new D;
px-> f(); // ошибка
px->I1::f(); // ошибка
((I1 *)px) -> f(); //Работает! Явное приведение
C#: Неявная и явная реализация интерфейсов
interface ISample
{
void f();
}
class CoClass: ISample
{
public void f(){…} // неявная реализация, «public» перед void f() обязателен
}
class CoClass2: ISample
{
void ISample.f(){…} // явная реализация. Запрещено указывать public, private, protected.
}
CoClass x = new CoClass();
x.f();// работает!
CoClass2 x = new CoClass2()’
x.f();/// ошибка! Цитата компилятора: «CoClass2' does not contain a definition for 'f'
((ISample)x).f(); // работает! Явное приведение
В платформе .Net имеется класс
class FileStream:IDisposable
{
….
void IDisposable.Dispose(){…;}
void Close(){ ((IDisposable)this).Dispose();}
….
}
FileStream реализует интерфейс IDisposable явным образом, т.е. через объект FileStream нельзя вызвать метод Dispose. Вместо этого имеется не виртуальный метод Close, который явно вызывается Dispose внутри себя.
class IControl
{
void Paint();
}
interface IEdit:IControl
{
…..
}
interface IDropList:Icontrol
{
…..