Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Лекция 3. Примеры использования класса

Примеры использования класса

Использование класса

Определение методов класса

Объявление методов класса

Лекция 2.

План:

1. Объявление методов класса

2. Реализация класса: общие положения

3. Определение конструкторов: примеры

4. Определение методов класса

5. Использование класса

6. Примеры использования класса

Объявление конструкторов: отсутствует тип возвращаемого значения (конструктор ничего не возвращает); имя конструктора совпадает с именем класса.

Прототипы конструкторов:

· пустой - имя_класса ();

· инициализирующие - имя_класса (тип имя_параметра,...); тип - любой, кроме имени_класса

· копирующий - имя_класса (const имя_класса & имя_параметра);

Объявление деструктора: также отсутствует тип возвращаемого значения (деструктор ничего не возвращает); имя деструктора совпадает с именем класса и начинается символом ~.

Прототип деструктора: ~ имя_класса ();

Объявление остальных методов: обычные прототипы функций С:

тип_возвращаемого_значения имя_функции (тип имя_параметра,...);

При объявлении прототипов функций возможно задание значений параметров по умолчанию:

тип_возвращаемого_значения имя_функции (тип имя_параметра,..., тип имя_параметра = значение,...);

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

Пример: класс Rational

class Rational{

private:

int num, den;

int gcd();

void reduce();

protected:

/* отсутствует: можно совсем не включать данную часть класса, вместе с ключевым словом */

public:

/* Конструкторы класса */

Rational();

Rational(int num); // 1

Rational(int num, int den); // 2

/* Деструктор класса */

~Rational();

/* Методы класса: селекторы */

void print();

Rational add(const Rational &opd);

/* Модификатор */

void assign(int x, int y);

};

В приведенном примере вместо двух конструкторов - 1 и 2 можно было указать один конструктор с параметром по умолчанию:

Rational(int num, int den = 1);

2. Реализация класса: общие положения

Определения функций-членов класса обычно размещаются вне класса и следуют обычным правилам языка С, за одним исключением: в начале возможно указание ключевого слова inline, определяющее встроенную функцию (правила вызова встроенных функций; определение inline-функций должны размещаться в файлах-заголовках, тогда как определения обычных функций - в обычных файлах):

[inline] тип_возвращаемого_значения имя_функции_члена_класса (тип параметр1,...)

{

... // тело функции

}

Ограничения на использование inline-функций.

Определения функций могут быть включены в определение класса - тогда получаем всегда и только inline-функции, поэтому внутри класса ключевое слово inline не кодируется.

В С++ можно любую функцию, не обязательно член класса, сделать inline-функцией.

Две особенности функций-членов: как задается имя функции и как осуществляется доступ к состоянию класса.

1. Задание имени функции-члена класса: имя функции-члена класса содержит в себе информацию о том классе, в котором эта функция (метод) определена. Функция-член класса не существует вне класса и без класса. Поэтому в задании имени функции-члена класса используются имя класса и операция разрешения видимости:

имя_класса:: имя_функции

При вызове функции (посылке сообщения адресату) указывается только имя_функции; имя_класса определяется типом адресата:

адресат. имя_функции (список_аргументов)

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

Внутри функций-членов класса определен специальный неявный параметр this - имеет тип “указатель на данный класс”; его значение определяет адресата - адрес конкретного экземпляра класса, которому посылается соответствующее сообщение (или для которого вызывается соответствующая функция-член класса). Возможен доступ к членам класса по этому указателю: this-> имя_члена_класса.

Если нет никаких неясностей и неопределенностей, имя_класса и/или this-> могут быть опущены.

 

3. Определение конструкторов: примеры

Реализация конструкторов класса Rational, определенного ранее.

class Rational{

private:

int num, den;

int gcd(); // Нахождение наибольшего общего делителя

void reduce(); // Сокращение дроби

void correct(); // Корректировка значения дроби (так чтобы всегда было den > 0)

protected:

public:

/* Конструкторы класса */

Rational(){num = 0; den = 1; }

Rational(int num){Rational::num = num; den = 1; }

Rational(int num, int den) {num = n; den = d; correct(); }

/* Второй вариант - с использованием параметров по умолчанию */

Rational(int num, int den = 1) {num = n; den = d; correct(); }

/* Деструктор класса */

~Rational(){}

/* Методы класса: селекторы */

void print();

Rational add(const Rational &opd);

/* Модификатор */

void assign(int x, int y);

};

Инициализирующие конструкторы обычно небольшие по размерам, поэтому их определение обычно включается в определение класса. Определение методов класса также можно включить в определение класса, если оно не велико. Но лучше вынести за пределы класса, используя при необходимости спецификатор inline.

inline void Rational::correct()

{

if(!den)

den = 1;

if(den < 0)

num = -num, den = -den;

}

inline void Rational::assign(int x, int y)

{

num = x;

den = y;

correct();

}

Видно, что две функции - двухаргументный конструктор и assign - имеют одинаковые коды; но это функционально разные функции - конструктор будет вызываться при объявлении и инициализации данных типа Rational, тогда как assign можно вызывать неоднократно - каждый раз, когда с помощью присваивания нужно изменить значение уже существующего экземпляра класса. Отличие такое же, как и в случае использования базовых типов:

int x = 1;... x = 1;...

#include <math.h>

int Rational::gcd()

{

int n = abs(num), d = abs(den), r;

while(r = n % d)

n = d, d = r;

return r;

}

void Rational::reduce()

{

int div = gcd();

num /= div;

den /= div;

}

Rational Rational::add(const Rational &opd)

{

Rational temp;

temp.num = num * opd.den + den * opd.num;

temp.den = den * opd.den;

temp.reduce();

temp.correct();

return temp;

}

void Rational::print()

{

cout << num;

if(den!= 1)

cout << ’/’<< den;

}

Конкретные объекты (экземпляры класса) создаются при локальном и внешнем объявлении данных в соответствии с обычными правилами С (С++). Они могут быть объявлены как простые переменные, массивы, указатели (для создания экземпляров класса в свободной памяти), члены-данные других классов, могут создаваться как временные переменные в процессе вычислений. Объявления экземпляров класса имеют специфический синтаксис только при инициализации объявляемых данных.

· Простые переменные:

Rational a, /* пустой конструктор; конструкция Rational a() определяет
обычную функцию, возвращающую значение типа Rational */

d(5), /* одноаргументный инициализирующий конструктор */

b(3,8); /* двухаргументный инициализирующий конструктор */

Возможна и традиционная инициализация экземпляров класса:

Rational c = 8, /* В результате будет создана дробь со значением 8/1 */

p = Rational(3,8); /* Так как при классической инициализации требуются значения соответствующего типа, а в языке не определены константы типа Rational, нужно построить такую константу, вызвав явно конструктор класса */

· Массивы:

Rational x[3], /* Используется пустой конструктор для создания каждого элемента
массива */

y[] = {2, 1, Rational(3,8)}; /* Обычный синтаксис при инициализации массива, обязательно используются значения соответствующего типа */

· Использование свободной памяти

Rational *ptr1, *ptr2;

ptr1 = new Rational(1,3); /* Классическое использование операции new, в которой указывается имя нового типа; при этом возможна сразу и инициализация выделенной области памяти за счет работы соответствующего конструктора */

ptr2 = new Rational[4]; /* Если выделяется память под массив, работает только пустой конструктор; инициализация памяти не выполняется */

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

Первый пример - различные способы определения объектов (простые переменные, массивы, динамические объекты) и вызов методов (посылка сообщений):

main()

{

Rational a(2), b[3], c(5,8), x, y;

a.print(); cout << endl;

b[1].print(); cout << endl;

x = a.add(c);

x.print(); cout << endl;

x.add(Rational(3,5)).print(); cout << endl;

/* Для свободной памяти */

Rational *ptr;

ptr = new Rational(3,8);

(*ptr).print(); cout << endl; /* Возможна и запись ptr->print(); */

}

Ошибки:

a.gcd()

a.reduce()

и т.п.

Второй пример - практическое использование класса для решения основной задачи (система двух уравнений с двумя неизвестными). Предполагается, что для класса Rational определены все арифметические операции: сложения (add), вычитания (sub), умножения (mul) и деления (div).

Решить систему вида:

ax + by = c

dx + ey = f

Решение имеет вид:

определитель системы det = a * e - d * b;

x = (c * e - b * f) / det; y = (a * f - d * c) / det;

Чтобы умножить a на e, нужно экземпляру a послать сообщение: “умножь себя (свое значение) на e”: a.mul(e);

main()

{

Rational a(...), b(...), c(...), d(...), e(...), f(...), x, y;

Rational det;

det = (a.mul(e)).sub(d.mul(b));

x = (c.mul(e)).sub(b.mul(f)).div(det);

y = (a.mul(f)).sub(d.mul(c)).div(det);

x.print(); cout << ’,’; y.print(); cout << endl;

}


План:

1. Перегрузка функций

2. Перегрузка операций

3. Выбор функции

4. Друзья класса

5. Друзья или члены

6. Преобразования типа

<== предыдущая лекция | следующая лекция ==>
Конструкторы и деструктор | 
Поделиться с друзьями:


Дата добавления: 2014-01-20; Просмотров: 579; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.01 сек.