|
|
От: | MTDIGSUT | |
| Дата: | 10.06.07 23:30 | ||
| Оценка: | 15 (4) +1 | ||
... осваиваю виртуальные функции и динамичский полиморфизм, но не могу понять зачем он нужен и как его реализовать этот динамический полиморфизм.
...
Думаю наглядный пример помог бы мне разобраться, но здесь на форуме я ничего понятного для меня я не нашел.
#include <iostream>
using namespace std;
class unary_operation { // Базовый класс. В контексте полиморфизма - интерфейс.
// Перечисление в нём виртуальных функций даёт компилятору достаточно информации,
// чтобы генерировать _единообразный_ код для вызова всех _различных_ виртуальных
// функций в производных классах (единый интерфейс).
public:
virtual int process (int a) { // Бывает удобно объявлять виртуальные функции базового
// класса чистыми виртуальными (без реализации),
// но тут без тонкостей.
cout << __PRETTY_FUNCTION__ << endl;
return a; // Отсутсвие операции.
};
};
// Далее идут три производных класса, изменяющие реализацию виртуальной функции.
class neg_operation : public unary_operation {
public:
virtual int process (int a) {
cout << __PRETTY_FUNCTION__ << endl;
return -a;
};
};
class abs_operation : public unary_operation {
public:
virtual int process (int a) {
cout << __PRETTY_FUNCTION__ << endl;
return a < 0 ? -a : a;
}
};
class zero_operation : public unary_operation {
public:
virtual int process (int a) {
cout << __PRETTY_FUNCTION__ << endl;
return 0;
}
};
int complex_algorithm (unary_operation* op, int another_argument) {
// Допустим, что в этой функции реализован "очень сложный" алгоритм, код которого
// тщательно проверен и сейчас является стабильным - изменять его крайне нежелательно.
// Как нам расширить возможности алгоритма без внесения изменений?
// ... Тут скрыта "сложная" часть. :)
// Современный подход заставить один и тот же кусок кода (буквально - одну и ту же
// оследовательность символов) делать что-то другое и при этом не изменять ни строчки кода -
// использовать полиморфизм (в данном случае - динамический).
cout << "Function called: " << endl;
// Например, в этой строке компилятор генерирует единственный возможный вариант машинного кода,
// но вызывается функция того объекта, на который указывает указатель переданный в функцию.
int result = op->process (another_argument);
return result;
}
unary_operation* get_operation () { // Эта функция просто создаёт объекты в зависимости от внешних данных.
// В жизни это может быть любой источник объектов. Код именно таких функций
// по идее часто нестабилен и сильно изменяется, но тот, кто с ней работает, уверен,
// что полученный объект "умеет" выполнять все действия из объявленного интерфейса
// (в данном случае - единственную функцию "int process (int)"),
// так как он поддерживает указанный единый интерфейс unary_operation.
int op_code;
cout << "1 - neg;" << endl;
cout << "2 - abs;" << endl;
cout << "3 - zero;" << endl;
cout << "anything else - exit program." << endl;
cout << "Enter desired operation:" << endl;
cin >> op_code;
// Добавьте сюда другую логику.
switch (op_code) {
case 1:
return new neg_operation ();
case 2:
return new abs_operation ();
case 3:
return new zero_operation ();
default:
return 0;
}
};
int main () {
// Выполнение одного и того же алгоритма с различными полиморфными объектами.
int i = 0;
unary_operation* op = get_operation ();
while (op) {
int result = complex_algorithm (op, ++ i);
cout << "Result = " << result << endl;
delete op;
op = get_operation ();
}
return 0;
};// Не изменяя следующий "набор символов", компилятор может приводить к
// выполнению различных действий (в зависимости от типа объекта).
template < class T >
void func (T& obj) {
// ...
obj.process ();
// ...
}