Студопедия  
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Пример 3

Читайте также:
  1. III. ПРИМЕРНАЯ СТРУКТУРА КУРСОВОЙ РАБОТЫ
  2. III.2. ПРИМЕРНАЯ ТЕМАТИКА РЕФЕРАТОВ, КУРСОВЫХ РАБОТ
  3. V. ПРИМЕРНАЯ ТЕМАТИКА РЕФЕРАТОВ
  4. VI. ПРИМЕРНЫЙ ПЕРЕЧЕНЬ ВОПРОСОВ К ЗАЧЕТУ
  5. Алгоритм. Свойства алгоритмов. Способы записи алгоритмов. Базовые структуры алгоритмов. Примеры.
  6. Алюминий и его сплавы. Классификация алюминиевых сплавов. Деформируемые алюминиевые сплавы. Дуралюмины, термическая обработка дуралюминов. Примеры, маркировка.
  7. Бесчерепные (на примере ланцетника)
  8. Билет 7. Понятие и типология коммуникационного взаимодействия (коммуникативных актов). Примеры.
  9. Билет №13. Крупнейшие действующие издательства России. Распределение мощностей. Государственные и негосударственные издательства в России (примеры).
  10. Будьте примером

#include <iostream.h>

void f(int a){

cout << "n m\n";

while (a--){

static int n = 0;

int m = 0;

cout << n++ << ' ' << m++ << '\n';

}}

int main(){ f(3);}

Статическая переменная n размещается в сегменте данных и инициализируется один раз при первом выполнении оператора, содержащего ее определение.

 

 

18. Дружественные функции и классы (С++).

Дружественные функции применяются для доступа к скрытым (private, protected) полям класса, т. е. это альтернатива методам.

В виде дружественных функций оформляются действия, которые не являются свойствами класса, но нуждающиеся в доступе к скрытым полям. Например, функции ввода/вывода.

Свойства дружественных функций:

• Дружественная функция объявляется внутри класса, к элементам которого ей нужен доступ, со спецификатором friend.

• В качестве параметра ей передается объект (ссылка на объект) класса, т. к. раз она не является членом класса, то ей не передается указатель this.

• На нее не распространяется действие спецификаторов доступа.

• Дружественная функция может быть глобальной функций или функций другого класса.

• Место ее расположения в классе безразлично.

• Одна функция может быть дружественной разным классам.

class person

{string name; int age;

public:

person() {age=0;name=””;}

person(string Name, int Age)

{name=Name; age=Age;}

friend void show(person a);//глобальная дружественная функция

};

void show(person a)

{ cout<<a.name<<” “<<a.age;}

Дружественный класс

Если все методы какого-либо класса должны иметь доступ к скрытым полям другого класса, то весь класс объявляется дружественным с помощью ключевого слова friend.

class A

{

……..

friend class B;

};

class B{…};

 

19. Способы обмена данными: с помощью глобальных переменных.

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

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

 

20. Перегрузка операций (С++).

Перегрузка арифметических операций, логических и прочих

C++ позволяет переопределить действие большинства операций так, чтобы при использовании с объектами конкретного класса они выполняли заданные функции.

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

Обозначения собственных операций вводить нельзя.

Унарная функция-операция, определяемая внутри класса,

должна быть представлена с помощью нестатического метода без параметров, при этом операндом является вызвавший ее объект

Person& operator++(Person &P)

{++age; return*this;}

Бинарная функция-операция, определяемая внутри класса,

должна быть представлена с помощью нестатического метода без параметров, должна быть пред­ставлена с помощью нестатического метода с параметрами, при этом вызвавший ее объект считается первым операндом

bool operator > (const Person &P)

{

if(age > P.get_age()) return true; return false;

}

Перегрузка операции =

• Операция присваивания определена в любом классе по умолчанию как поэлементное копирование.

• Эта операция вызывается каждый раз, когда одному существующему объекту присваивается значение другого.

• Если класс содержит поля, память под которые выделяется динамически, необходимо определить собственную операцию присваивания.

• Чтобы сохранить семантику присваивания, операция-функция должна возвращать ссылку на объект, для которого она вызвана, и принимать в качестве параметра единственный аргумент — ссылку на присваиваемый объект.

• Операцию присваивания можно определять только как метод класса.

• Операция присваивания не наследуется.

Person& operator=(const&Person);

….

};

Person& Person:: operator= (const Person&P)

 

 

Инициализация:

<возвращаемый тип> operator<знак операции>(<аргументы>)

{<тело>;}

compl& operator –(compl&); - описание

compl& compl::operator-(compl&m); -определение

21. Способы обмена данными: Возвращаемое значение.

Возврат из функции в вызвавшую ее функцию реализуется оператором

return [ выражение ];

Функция может содержать несколько операторов return. Если функция описана как void, выражение не указывается. Выражение, указанное после return, неявно преобразуется к типу возвращаемого функцией значения и передается в точку вызова функции.

Примеры:

int f1(){return 1;}//правильноvoid f2(){return 1;}//неправильно, f2 не должна возвращать значениеdouble f3{return 1;}//правильно, 1 преобразуется к типу double

ВНИМАНИЕ

Нельзя возвращать из функции указатель на локальную переменную.

 

22. Наследование (С++, Паскаль).

Наследование - один из основополагающих принципов объектно-ориентированного программирования. Под наследованием понимают возможность объявления производных типов на основе ранее объявленных типов. Как известно, в C++ существует фиксированное множество элементарных типов. Это абсолютно независимые типы и объявление одного элементарного типа на основе другого в принципе невозможно.

Спецификации объявления unsigned int или long double нельзя рассматривать как модификации элементарных типов int и double. Это полноправные элементарные типы данных со своим собственным набором свойств. В C++ также невозможно определить одну функцию на основе другой ранее определённой (правда, в C++ существует понятие шаблона функции, и мы обязательно обратимся к этому вопросу).

И вот, наконец, для класса, в C++ реализуется возможность наследования. Прежде всего, следует различать наследование и встраивание. Встраивание предполагает возможность объявления в классе отдельных членов класса на основе ранее объявленных классов. В классе можно объявлять как данные-члены основных типов, так и данные-члены ранее объявленных производных типов.

В случае же наследования новый класс в буквальном смысле создаётся на основе ранее объявленного класса, НАСЛЕДУЕТ, а возможно и модифицирует его данные и функции. Объявленный класс может служить основой (базовым классом) для новых производных классов. Производный класс наследуют данные и функции своих базовых классов и добавляют собственные компоненты.

В C++ количество непосредственных "предков" производного класса не ограничено. Класс может быть порождён от одного или более классов. В последнем случае говорят о множественном наследовании. Наследование в C++ реализовано таким образом, что наследуемые компоненты не перемещаются в производный класс, а остаются в базовом классе. Производный класс может переопределять и доопределять функции-члены базовых классов. Но при всей сложности, наследование в C++ подчиняется формальным правилам. А это означает, что, во-первых, существует фиксированный набор алгоритмов, которые позволяют транслятору однозначно различать базовые и производные компоненты классов, а во-вторых, множество вариантов наследования ограничено.

 

23. Способы обмена данными: Параметры функции.

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

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

Существует два вида передачи величин в функцию: по значению и по адресу.

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

При передаче по адресу в стек заносятся копии адресов параметров, а функция осуществляет доступ к ячейкам памяти по этим адресам и может изменить исходные значения параметров:

#include <iostream.h>void f(int i, int* j, int& k);int main(){int i = 1, j = 2, k = 3; cout <<"i j k\n"; cout << i <<' '<< j <<' '<< k <<'\n'; f(i, &j, k); cout << i <<' '<< j <<' '<< k;}void f(int i, int* j, int& k){i++; (*j)++; k++;}

Результат работы программы:

i j k 1 2 31 3 4

Первый параметр (i) передается по значению. Его изменение в функции не влияет на исходное значение.

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

Третий параметр (k) передается по адресу с помощью ссылки.

При передаче по ссылке в функцию передается адрес указанного при вызове параметра, а внутри функции все обращения к параметру неявно разыменовываются. Поэтому использование ссылок вместо указателей улучшает читаемость программы. Использование ссылок вместо передачи по значению более эффективно, поскольку не требует копирования параметров.

Если требуется запретить изменение параметра, используется модификатор const:

int f(const char*);char* t(char* a, const int* b);

СОВЕТ

Рекомендуется указывать const перед всеми параметрами, изменение которых в функции не предусмотрено. Это облегчает отладку. Кроме того, на место параметра типа const& может передаваться константа.

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

 

24. Виртуальные методы и абстрактные классы.

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

class employee {
char* name;
short department;
//...
employee* next;
static employee* list;
public:
employee(char* n, int d);
//...
static void print_list();
virtual void print() const;

};

Служебное слово virtual (виртуальная) показывает, что функция print() может иметь разные версии в разных производных классах, а выбор нужной версии при вызове print() - это задача транслятора. Тип функции указывается в базовом классе и не может быть переопределен в производном классе. Определение виртуальной функции должно даваться для того класса, в котором она была впервые описана (если только она не является чисто виртуальной функцией, см. $$6.3). Например:

void employee::print() const
{
cout << name << '\t' << department << '\n';
//...
}

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

class manager: public employee {
employee* group;
short level;
//...
public:
manager(char* n, int d);
//...
void print() const;
};

Место функции print_employee() заняли функции-члены print(), и она стала не нужна. Список служащих строит конструктор employee ($$6.2.2). Напечатать его можно так:

void employee::print_list()
{
for (employee* p = list; p; p=p->next) p->print();
}

Данные о каждом служащем будут печататься в соответствии с типом записи о нем. Поэтому программа

int main()
{
employee e("J.Brown",1234);
manager m("J.Smith",2,1234);
employee::print_list();
}

напечатает

J.Smith 1234
level 2
J.Brown 1234

Обратите внимание, что функция печати будет работать даже в том случае, если функция employee_list() была написана и оттранслирована еще до того, как был задуман конкретный производный класс manager! Очевидно, что для правильной работы виртуальной функции нужно в каждом объекте класса employee хранить некоторую служебную информацию о типе. Как правило, реализации в качестве такой информации используют просто указатель. Этот указатель хранится только для объектов класса с виртуальными функциями, но не для объектов всех классов, и даже для не для всех объектов производных классов. Дополнительная память отводится только для классов, в которых описаны виртуальные функции. Заметим, что при использовании поля типа, для него все равно нужна дополнительная память.

Если в вызове функции явно указана операция разрешения области видимости::, например, в вызове manager::print(), то механизм вызова виртуальной функции не действует. Иначе подобный вызов привел бы к бесконечной рекурсии. Уточнение имени функции дает еще один положительный эффект: если виртуальная функция является подстановкой (в этом нет ничего необычного), то в вызове с операцией:: происходит подстановка тела функции. Это эффективный способ вызова, который можно применять в важных случаях, когда одна виртуальная функция обращается к другой с одним и тем же объектом. Пример такого случая - вызов функции manager::print(). Поскольку тип объекта явно задается в самом вызове manager::print(), нет нужды определять его в динамике для функции employee::print(), которая и будет вызываться.

 

25. Передача параметров по значению и по адресу.

 

26. Модули в Delphi. Структура описания модуля. Назначение модуля.

Модульное программирование – это организация программы как совокупности небольших независимых блоков, называемых модулями, структура и поведение которых подчиняются определенным правилам.

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

n Основное назначение модуля – объединение и надежное скрытие деталей реализации определенной подзадачи.

СТРУКТУРА МОДУЛЯ

Unit <имя>;




Дата добавления: 2015-02-16; просмотров: 16 | Поможем написать вашу работу | Нарушение авторских прав




lektsii.net - Лекции.Нет - 2014-2024 год. (0.011 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав