Слайд 1 - SAT@home

advertisement
Основы информатики
Классы. Часть 2
Заикин Олег Сергеевич
zaikin.icc@gmail.com
Массивы объектов
Пример программы, в которой используется статический массив
из 3-ех объектов. В ней создается класс display, который
содержит разрешения для различных режимов монитора.
Массивы объектов
Указатели на объект
Указатели на объект можно использовать, когда необходимо
создать объект в процессе работы программы.
employee *a; // указатель на объект класса
a = new employee(); // выделяется память под объект
… // действия с объектом
delete a; // освобождение памяти объекта
Также можно создать динамический массив объектов.
vector<employee> vec_emp; // динамический массив объектов
employee a;
… // заполнение объекта a
vec_emp.push_back( a ); // добавим объект в массив
Обращение к элементам класса
Прямое обращение – через оператор .
myclass object;
object.property = 3;
Косвенное – через ->
Обращение к элементу объекта через указатель на этот объект.
myclass *pobject; // указатель на объект класса myclass
pobject->property = 3;
или
(*pobject).property = 3;
Указатель this
Всякий раз, когда вызывается функция-член, автоматически
передается указатель на объект, вызывающий данную функцию.
Можно получить доступ к этому указателю, используя this.
Указатель this служит неявным параметром всех функцийчленов. (Функции-друзья не имеют указателя this.) Например, в
операторе:
оb.f();
функции f() автоматически передается указатель this,
указывающий на объект ob.
Указатель this
Как известно, функции-члены имеют непосредственный доступ к
данным класса. Например, если задан следующий класс:
class cl
{
int i;
// ...
};
то функция-член может присвоить переменной i значение 10,
используя следующую инструкцию:
i = 10;
Фактически эта инструкция является сокращенной записью
следующий инструкции:
this->i = 10;
Указатель this
Для того, чтобы увидеть, как работает указатель this, рассмотрим
следующую короткую программу:
#include <iostream.h>
class cl {
int i;
public:
void load_val(int val) { this->i = val; }
int get_val() { return this->i; }
};
int main ()
{
cl o;
o.load_i(100);
cout << o.get_i();
return 0;
}
Эта программа выводит на экран число 100.
Указатель this
В таком использовании указателя this нет никаких преимуществ,
так как данные конкретных объектов доступны в принадлежащих
классу функциях и с помощью имен данных класса.
Однако в некоторых случаях указатель this полезен, а иногда
просто незаменим. В следующем примере указатель this
позволяет компилятору разобраться в ситуации, когда имя
Meaning компонента класса совпадает с именем формального
параметра принадлежащей классу функции:
class cell // Класс "числовой элемент".
{
double Meaning;
public: // Конструктор:
cell(double Meaning = 0.0) {this->Meaning = Meaning; }
}
Наследование
Наследование — механизм языка, позволяющий написать
новый класс на основе уже существующего базового класса.
Производный класс может добавить собственные методы и
свойства и пользоваться базовыми методами и свойствами.
Позволяет строить иерархии классов.
Наследование
Пример 1.
Четырехугольник.
Параллелограмм – четырехугольник, у которого противоположные
стороны попарно равны и параллельны.
Прямоугольник - параллелограмм, у которого все углы прямые.
Ромб – параллелограмм, у которого все стороны равны.
Квадрат – прямоугольник, у которого все стороны равны.
Дерево классов:
Четырехугольник -> Параллелограмм - > Прямоугольник -> Квадрат
-> Ромб
Наследование
Пример 2.
Кошка имеет свойства:
• мех (короткий или длинный)
• хвост (есть или нет)
У кошек Сиамской породы короткий мех и есть хвост.
У кошек породы Мэнкс длинный мех и нет хвоста.
Кошка -> Сиамская (хвост есть, мех короткий)
-> Мэнкс (хвоста нет, мех длинный)
Наследование
Общий формат наследования.
class имя_производного_класса : доступ имя_базового_класса
{
// описание нового класса
}
Доступ может быть public, private или protected.
Наследование
Если класс объявлен как базовый для другого класса со
спецификатором доступа public, тогда public элементы базового
класса доступны как public элементы производного класса,
protected члены базового класса доступны как protected члены
производного класса.
Наследование
class A{ //базовый класс };
class B : public A{ //public наследование
};
class C : protected A{ //protected наследование
};
class Z : private A{ //private наследование
};
Наследование. Пример
class employee
{
public:
employee();
void show_employee(void);
char name[64];
private:
char position[64];
float salary;
};
class manager : public employee
{
public:
manager();
void show_manager(void);
private:
float annual_bonus;
char company_car[64];
int stock_options;
};
employee a;
manager b;
a.name = “John”;
b.name = “Jack”; // доступ к переменной базового класса
Модификаторы доступа
private - закрытые элементы, будут использоваться только
внутри своего собственного класса.
public – открытые элементы, могут быть использованы в других
частях программы, либо в других классах.
protected – доступ к элементу открыт классам, производным от
данного.
private-элементы наследуются, но не могут быть использованы в
производных классах. Чтобы производный класс мог обратиться
к закрытым элементам базового, элемент должен быть объявлен
не как private, а как protected.
Наследование
class CBase
{
private: int privateBase;
protected: int protBase;
public: int pubBase;
};
Ни один из наследников не сможет получить доступ к privateданным CBase. Как у них сложатся отношения с остальными
данными зависит от того, как они были наследованы.
private наследование
Те данные, что в CBase были protected и public, стали private в
CDerived.
Наследование
class CDerived : private CBase {
//унаследованные данные класса
//недоступно:
// int privateBase;
//private:
// int protBase;
//private:
// int pubBase;
public:
void updateDerived()
{
//privateBase=0;
//нельзя доступиться к private данным CBase
protBase=0;
pubBase=0;
}
};
Встраиваемые функции
Встраиваемой называется небольшая (по объему кода)
функция, код которой подставляется вместо ее вызова.
Нужны для повышения эффективности программы. Так простые
функции вызываются быстрее.
Способ 1.
Используется ключевое слово inline
class cl {
int i;
public:
int get_i();
};
Inline cl :: get_i{ return i };
Реализация встраиваемой функции должна быть в заголовочном
файле (в отличие от невстроенных функций класса).
Встраиваемые функции
Способ 2.
Код функции добавляется в определении класса
class cl {
int i;
public:
int get_i{ return i };
};
Если тело функции находить в файле *.h, то функция по
умолчанию становиться inline.
Функции класса, состоящие из двух или более строк, лучше
определять по способу 1.
В некоторых компиляторах есть ограничения, не позволяющие
делать встроенными функции, в которых есть циклы.
Друзья
Иногда удобно разрешить некоторым функциям доступ к
закрытым членам класса. Механизм друзей позволяет классу
разрешать доступ к своим неоткрытым членам.
Объявление друга начинается с ключевого слова friend и может
встречаться только внутри определения класса.
Так как друзья не являются членами класса, то не имеет
значения, в какой секции они объявлены (public, private или
protected).
Друзья
class Screen {
public:
friend istream& operator>>( istream&, Screen& );
friend ostream& operator<<( ostream&, const Screen& );
void home() { _cursor = 0; }
char get() { return screen[cursor]; }
char get( int, int );
void move( int, int );
private:
string screen;
string::size_type cursor;
short height, width;
};
Операторы ввода и вывода теперь могут напрямую обращаться к
закрытым членам класса Screen. Простая реализация оператора
вывода выглядит следующим образом:
Друзья
stream& operator<<( ostream& os, const Screen& s )
{ // можно обращаться к height, width и screen
os << "<" << s.height
<< "," << s.width << ">"
os << s.screen;
return os;
}
Теперь можно вывести содержимое класса напрямую
Screen scr;
// действия с объектом scr
std::cout << scr; // вывод закрытых полей класса
Download