Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
c++ 2.0.docx
Скачиваний:
4
Добавлен:
25.09.2019
Размер:
77.41 Кб
Скачать

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

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

Фактический или формальный

По способу применения различают:

фактический параметр — аргумент, используемый как значение (число, символ и т. д.);

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

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

Особенности использования: формального параметра: аргумент должен быть определён вне функции;

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

#include <iostream>

using namespace std;

int actual_p(int n)

{

n = 1;

return n;

}

int formal_p(int &n)

{

n = 1;

return n;

}

int main()

{

int iActual = 0;

int iFormal = 0;

cout << "Начальное значение переменной: " << iActual << endl;

cout << "Аргумент передан как фактический параметр и изменён: " << actual_p(iActual) << endl;

cout << "Конечное значение переменной: " << iActual << endl;

cout << "Начальное значение переменной: " << iFormal << endl;

cout << "Аргумент передан как формальный параметр и изменён: " << formal_p(iFormal) << endl;

cout << "Конечное значение переменной: " << iFormal << endl;

return 0;

}

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

Начальное значение переменной: 0

Аргумент передан как фактический параметр и изменён: 1

Конечное значение переменной: 0

Начальное значение переменной: 0

Аргумент передан как формальный параметр и изменён: 1

Конечное значение переменной: 1

Как видно из работы программ: фактический параметр — значение аргумента; формальный параметр — имя аргумента, то есть указатель на переменную.

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

в объектно-ориентированном программировании метод (функция) класса, который может быть переопределён в классах-наследниках так, что конкретная реализация метода для вызова будет определяться во время исполнения. Таким образом, программисту необязательно знать точный тип объекта для работы с ним через виртуальные методы: достаточно лишь знать, что объект принадлежит классу или наследнику класса, в котором метод объявлен.

Виртуальные методы — один из важнейших приёмов реализации полиморфизма. Они позволяют создавать общий код, который может работать как с объектами базового класса, так и с объектами любого его класса-наследника. При этом базовый класс определяет способ работы с объектами и любые его наследники могут предоставлять конкретную реализацию этого способа

Базовый класс может и не предоставлять реализации виртуального метода, а только декларировать его существование. Такие методы без реализации называются «чистыми виртуальными» (перевод англ. pure virtual) или абстрактными. Класс, содержащий хотя бы один такой метод, тоже будет абстрактным. Объект такого класса создать нельзя (в некоторых языках допускается, но вызов абстрактного метода приведёт к ошибке). Наследники абстрактного класса должны предоставить реализацию для всех его абстрактных методов, иначе они, в свою очередь, будут абстрактными классами. Для каждого класса, имеющего хотя бы один виртуальный метод, создаётся таблица виртуальных методов. Каждый объект хранит указатель на таблицу своего класса. Для вызова виртуального метода используется такой механизм: из объекта берётся указатель на соответствующую таблицу виртуальных методов, а из неё, по фиксированному смещению, — указатель на реализацию метода, используемого для данного класса. При использовании множественного наследования или интерфейсов ситуация несколько усложняется за счёт того, что таблица виртуальных методов становится нелинейной.

Пример виртуальной функции на C++

Пример на C++, иллюстрирующий отличие виртуальных функций от невиртуальных:

class Ancestor

{

public:

virtual void function1 () { cout << "Ancestor::function1()" << endl; }

void function2 () { cout << "Ancestor::function2()" << endl; }

};

class Descendant : public Ancestor

{

public:

virtual void function1 () { cout << "Descendant::function1()" << endl; }

void function2 () { cout << "Descendant::function2()" << endl; }

};

Descendant* pointer = new Descendant ();

Ancestor* pointer_copy = pointer;

pointer->function1 ();

pointer->function2 ();

pointer_copy->function1 ();

pointer_copy->function2 ();

В этом примере класс Ancestor определяет две функции, одну из них виртуальную, другую — нет. Класс Descendant переопределяет обе функции. Однако, казалось бы одинаковое обращение к функциям даёт разные результаты. На выводе программа даст следующее:

Descendant::function1()

Descendant::function2()

Descendant::function1()

Ancestor::function2()

То есть, в случае виртуальной функции, для определения реализации функции используется информация о типе объекта и вызывается «правильная» реализация, независимо от типа указателя. При вызове невиртуальной функции, компилятор руководствуется типом указателя или ссылки, поэтому вызываются две разные реализации function2(), несмотря на то, что используется один и тот же объект.

Следует отметить, что в С++ можно, при необходимости, указать конкретную реализацию виртуальной функции, фактически вызывая её невиртуально: pointer->Ancestor::function1 (); для нашего примера выведет Ancestor::function1(), игнорируя тип объекта

Абстрактный класс в объектно-ориентированном программировании — базовый класс, который не предполагает создания экземпляров. Абстрактные классы реализуют на практике один из принципов ООП - полиморфизм. Абстрактный класс может содержать (и не содержать[1]) абстрактные методы и свойства. Абстрактный метод не реализуется для класса, в котором описан, однако должен быть реализован для его неабстрактных потомков. Абстрактные классы представляют собой наиболее общие абстракции, то есть имеющие наибольший объем и наименьшее содержание. Абстрактный класс можно рассматривать в качестве интерфейса к семейству классов, порождённому им, но, в отличие от классического интерфейса, абстрактный класс может иметь определённые методы, а также свойства. Абстрактные методы часто являются и виртуальными, в связи с чем понятия «абстрактный» и «виртуальный» иногда путают.

C++

На языке программирования C++ абстрактный класс объявляется включением хотя бы одной чистой виртуальной функции, типа virtual _сигнатура_функции_ =0;, которая как и другие может быть заменена. Пример на языке программирования C++:

#include <iostream>

class CA { // Абстрактный класс

public:

CA ( void ) { std::cout << "This object of the class "; }

virtual void Abstr ( void ) = 0; // Чистая (пустая) виртуальная функция.

void fun ( void ) { std::cout << "Реализация не будет наследоваться!"; }

~CA () { std::cout << "." << std::endl; } //Вызывается в обр. порядке конструкторов

};

class CB : public CA {

public:

CB ( void ) { std::cout << "CB;"; }

void Abstr ( void ){ std::cout << " call function cb.Abstr();"; } //Подменяющая функция.

void fun ( void ){ std::cout << " call function cb.fun()"; }

~CB () {} // Неверно для абстр. кл. ~CB(){ ~CA(); }

};

class CC : public CA {

public:

CC ( void ) { std::cout << "CC;"; }

void Abstr ( void ) { std::cout << " call function cc.Abstr();"; } //Подменяющая функция.

void fun ( void ) { std::cout << " call function cc.fun()"; }

~CC () {} // Неверно для абстр. кл. ~CC(){ ~CA(); }

};

int main () {

std::cout << "Program:" << std::endl;

CB cb;

cb.Abstr(); cb.fun(); cb.~CB();

CC cc;

cc.Abstr(); cc.fun(); cc.~CC();

return 0;

}

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

Program:

This object of the class CB; call function cb.Abstr(); call function cb.fun().

This object of the class CC; call function cc.Abstr(); call function cc.fun().

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]