- •Конструктор копирования (KK) может вызываться явно, а также при определении объекта в сочетании
- •Переопределение операций внутри класса
- •если формальный параметр или результат переда-ются
- •приведение типа - особенность операции – отсутствие
- •Переопределение операции () позволяет использовать
- •Переопределение операций распределения памяти class memory{
- •void free(void *q0) {
- •Классы стандартных потоков ввода-вывода
- •Перегрузка функций
- •Функции void Func(int); int Func(int);
- •Для того чтобы объекты, в состав которых входят
- •выделить в памяти место под объект создать «пустой»
- •Основная сущность полиморфизма - в возможности
- •При переходе от объекта производного класса к внут-
- •class A {
- •Внешний полиморфизм – ср-во объединения классов
- •Внутренний полиморфизм как элемент «отложенного»
- •примеры «отложенного» программирования:
- •Простые алгоритмы – взять составные части и
Классы стандартных потоков ввода-вывода
Переопределение операций - ввести единую интерпретацию операций по отношению ко всем базовым типам данных и разрабатываемым классам, в т.ч. и стандартного ввода-вывода. библиотека iostream.h
class istream{…
istream &operator>>(int v){sсanf(“%d”,&v); return *this; } istream &operator>>(float v){scanf(“%f”,&v); return *this; } istream &operator>>(char c){ … }
istream &operator>>(char c[]){ … } void getline(char c[],int n){}
};
class ostream{…
ostream &operator<<(int v){ printf(“%d”,&v); return *this; } ostream &operator<<(float v){ printf(“%f”,&v); return *this; } ostream &operator<<(char c){ … }
ostream &operator<<(char c[]){ … } };
extern istream cin; extern ostream cout;
В классах istream и ostream переопределены операции >> и
<< для всех базовых типов данных и массивов сим-волов cin = __stdin_streambuf; // attach the standard files cout = __stdout_streambuf; //to the standard streams Это позволяет записывать выражения вида
cout << a << b << “AAAAAA”; cin >> a >> b; операндами в кот могут быть переменные и выражения базовых типов, а также массивы символов (строки).
Чтобы стандарт потоки ввода-вывода «понимали» объекты разрабатыв. классов - переопределить операцию вида ostream << newclass и istream >> newclass - только в виде дружеств операт в пользовательском классе newclass.
class newclass{…
friend operator ostream& <<(ostream &O, newclass &R) {… O << R.vv… return O; }
friend operator istream& <<(istream &O, newclass &R) {… O >> R.vv… return O; }}
Аналогично def классы файловых и строковых потоков fstream, ifstream, ofstream, istrstream, ostrstream + конструкторы и методы
Перегрузка функций
С++ позволяет определять в программе произвольное кол- во функций с одним именем при условии, что все они имеют разный состав параметров (разное количество или разные типы пара-метров). Состав параметров функции иногда называют ее сигнатурой. При вызове перегруженной функции в программе компилятор анализирует ее сигнатуру и выбирает из списка одноименных функций ту, сигнатура которой соответствует вызванной. Например, функции с прототипами
void Func(int); void Func(int,int); void Func(char*);
являются перегруженными; при вызове функции Func() с одним целочисленным аргументом будет вызвана первая функция, при вызове функции с тем же именем, но с двумя целочисленными ар-гументами – вторая, а при указании в качестве аргумента адреса символьной строки – третья. При этом возвращаемый функцией тип роли не играет.
Функции void Func(int); int Func(int);
не являются перегруженными, компилятор их не различает, и, следовательно, такая пара функций не имеет права на существование. Перегрузка конструкторов Перегрузка конструкторов приобретает особое значение,
так как в классе, как правило, приходится определять несколько конструкторов с разными списками параметров. Наличие нескольких функций-конструкторов, имеющих одно имя, но разный состав параметров, возможно благодаря реализации в языке С++ средства перегрузки функций.
Рассмотрим для примера вариант класса Men, объекты которого можно записывать на диск. В прежних вариантах этого класса имя человека хранилось в объекте в виде указателя на символы, т. е. в виде адреса строки с именем, которая сама располагалась где-то в другом месте памяти – нельзя хранить на диске в таком виде, потом прочитаете только адрес.
Для того чтобы объекты, в состав которых входят
символьные строки, можно было хранить на диске, в класс необходимо включать не указатели на строки, а сами строки, а в конструкторе класса выполнять не присваивание, а копирование:
class Men{
char name[20];//Будем надеяться, что этого хватит int age;
public:
Men(char* n, int a){ strcpy(name,n;) age=a;
} }; Создаются объекты такого класса обычным образом:
Men m1("Иванов",18);
Men* pm2=Men("Петров", 22);
Такие объекты можно будет хранить на диске (для этого в состав класса придется включить ф-ю, реализующую запись объекта в файл на диске), но при чтении данного с диска в памяти должно быть зарезервировано место, т.е. должны выделить в памяти место под объект
выделить в памяти место под объект создать «пустой»
объект этого класса Чтобы можно было создать такой «пустой» объект, в состав
класса следует ввести перегруженный конструктор без параметров (такой конструктор называют конструктором по умолчанию):
Men(){}
Такой конструктор ничего не делает, он только выделяет в па-мяти место под объект.
Варианты предложений создания «пустых» объектов будут иметь такой вид:
Men m1;
Men* pm2=new Men();
Основная сущность полиморфизма - в возможности
одновременно рассматривать один и тот же объект и как абстрактную сущность, на уровне которой он совместим с объектами других классов, и как сущность конкретную. Сам же механизм
полиморфных методов обеспечивает автоматическое
преобразование I представления во II во время работы программы.
Свойство полиморфности заключается в том, что при отсутствии полной информации о том, к какому из классов относится объект, функция (метод) в состоянии идентифицировать его класс и корректно выполниться в нем Этим самым создается иллюзия единой ф-ии в каждом из родственных классов – виртуальные ф-и.
Полиморфизм система родовых классов, в которой базовый класс порождает множество производных (непосредственно, либо путем цепочки наследований). В этой системе возможны переходы, связанные со сменой представлений.
При переходе от объекта производного класса к внут-
реннему объекту базового класса происходит абстра- гирование его сущности, а также потеря его конкрет-ных св-в - расширение. Обратный переход от объекта базового класса к объемлющему его объекту производ-ного - сужение и сопровождается конкретизацией его св-в.
В С (С++) ! способ смены интерпретации содержимого памяти (фактически преобразов. формы представления переменной или объекта при сохранении содержи-мого памяти) – преобразов. типа указателя (если рассматр несвязанные типы данных - машинно-ориентирован-ное – физич уровень представления данных в памяти)
Базовый и производный классы - доп. интерпретация - преобразуя указатель на объект производного класса к указателю на объект базового, получаем доступ к вложенному объекту базового класса – расширение, всегда корректно и поэтому может производиться без явного использования операции преобразования типа указателя - транслятор «забывает» об объекте произ- водного класса и вместо переопределенных в нем ме- тодов вызывает методы базового (остальные преоб- разования типов указателей должны быть явными)
class A { |
f1(){} |
|
|
public: void |
|
||
}; |
|
|
|
class B : A { |
f1(){} |
// Переопределена в классe B |
|
public: void |
|||
void |
f2(){} |
|
|
}; |
|
|
|
void main(){ |
|
|
|
B |
x; |
// Прямое преобр (расширение) - неявное |
|
A *pa = &x; |
|||
pa->f1(); // Вызов A::f1(), хотя внутри объекта класса B |
|||
pb = (B*) pa; |
// Обратное преобр (сужение) – явное |
pb ->f2(); } // Корректно, если под pa был объект класса B После преобразования указателя на объект класса B в указатель на объект класса A происходит вызов ф-и из вложенного объекта базового класса A::f1(), хотя реально под указателем находится объект класса B.
Обратное преобразование от указателя на базовый класс к указателю на производный - только явно: будет корректно, если данный объект базового класса действительно содержится в объекте того производ-ного класса, к типу которого производится преобр указателя – иначе - динамич ошибка приведения типов - ошибка
времени выполнения, возникает или нет.
Внешний полиморфизм – ср-во объединения классов
Наличие общего базового класса - объединить в об-щую структуру данных объекты различной природы, приведя указатели на них к этому классу. Наличие в нем виртуальной ф-и - организовать регулярный про-цесс обработки данных, между которыми, в принципе, может и не быть ничего общего, кроме самого факта объединения и наличия общей ф-и обработки.
Наполнение общего базового класса может быть различным в зависимости от наличия у производных классов общего функционального наполнения:
· производные классы представляют собой вариации одной общей сущности, их общее функциональное наполнение может быть вынесено в базовый класс.
· производные классы не имеют никакой общей основы в виде данных и алгоритмов. Тогда виртуальные функции в базовом классе играют роль интерфейса (в терминах Java), позволяющего подключать объекты этого класса к общей системе обработки, требующей от них поддержки определенного обобщенного свойства.