Множественное наследование классов

Рассмотренная выше иерерхия классов графических объектов представ­ляет обычное (одиночное) наследование, когда производный класс на­следует од­ному конкретному базисному классу, расширяя его возможно­сти. Как было показано выше (см. пример 37), класс (потомок) может иметь бо­лее одно­го базисного класса (родителей).

В общем случае, класс создается из решетки Множественное наследование классов базисных классов. Так как исторически совокупы связей меж классами создавали деревья, ре­шетку классов нередко также именуют иерерхией классов. Классы пробуют проектировать так, чтоб юзера без необходимости не заинтересовывало, ка­ким образом класс составляется из других классов. А именно, механизм вир­туальных вызовов гарантирует, что когда мы вызываем функцию Множественное наследование классов f() для некото­рого объекта, вызывается одна и та же функция, независимо от того, какой класс в иерархии содержит объявление f(), использованное для вызова. Рассмот­рим особенности множественного наследования более тщательно на последующем модельном примере.

Пусть класс Task (задачка) определяет решаемые задачки:

class Task

{ // ...

public:

delay(int);

void wait();

void check(Task Множественное наследование классов*);

};

а класс Display (отображение) – вывод данных:

class Display

{ // ...

public:

void draw();

void write (Display*);

};

На их базе определим производный класс Device (прибор):

class Device: public Task, public Display

{ // ...

public:

void transmit();

};

Не считая операций, определенных для Device, можно пользоваться объединением операций Task и Display. К примеру:

void f (Device Множественное наследование классов& s)

{ s.draw(); // Display::draw()

s.delay(10); // Task::delay()

s.transmit(); // Device::transmit()

}

Виртуальные функции работают как обычно. К примеру:

class Task

{ // ...

virtual void wait()=0;

};

class Display

{ // ...

virtual void draw()=0;

};

class Device: public Task, public Display

{ // ...

void wait(); // замещение Task::wait()

void draw(); // замещение Display::draw()

}

Таковой подход гарантирует, что функции Device::draw() и Device Множественное наследование классов::wait() будут вызваны для класса Device, интерпретированного как Display и Task со­ответственно.

Разрешение неоднозначности.

Два базисных класса могут иметь способы с схожим именованием. Напри­мер:

class Task

{ // ...

virtual info* debug();

};

class Display

{ // ...

virtual info* debug();

};

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

void f (Device* pd)

{ info* d;

d=pd->debug(); // ошибка: разносторонне

d=pd->Task::debug(); // верно

d=pd->Display::debug(); // верно

}

Повторяющиеся базисные классы.

При задании более чем 1-го класса появляется возможность того, что ка­кой-либо класс два раза окажется базисным для другого класса. К примеру, если б любой из классов Множественное наследование классов Task и Display был производным от класса Link, у Device было бы два Link:

class Link

{ // ...

Link* next; // указатель на перечень

};

class Task: public Link

{ // Link употребляется для хранения перечня задач Task

// ...

};

class Display: public Link

{ // Link употребляется для хранения перечня объектов Display

// ...

};

Это не вызывает никаких заморочек. Употребляются два отдельных объекта Link для представления связей Множественное наследование классов, и эти списки не ведут взаимодействие вместе. Естественно, обращаясь к элементам класса Link, вероятна неоднозначность, требующая разрешения, как показано выше. Объект Device можно представить в графическом виде последующим образом:

Link Link

Task Display

Device

Обычно, базисный класс, который повторяется (как Link) является де­талью реализации, которую не следует использовать вне конкретно производных Множественное наследование классов от него классов. Если к такому базисному классу нужен доступ из места, где видна более чем одна копия базисного класса, во избежание неодно­значности ссылка должна быть очевидно квалифицирована. К примеру:

void links (Device* p)

{ p->next=0; // ошибка: разносторонне, какой Link?

p->Link::next=0; // ошибка: разносторонне Множественное наследование классов, какой Link?

p->Task::Link::next=0; // верно

p->Display::Link::next=0; // верно

};

Это в точности тот же механизм, который употребляется для разрешения неоднозначности при воззвании к элементам классов.

Виртуальные базисные классы.

В тех случаях, когда общий базисный класс не должен быть представлен в виде 2-ух отдельных объектов, необходимо пользоваться виртуальным базисным классом Множественное наследование классов. К примеру:

class Link

{ //...

};

class Task: public virtual Link

{ // ...

};

class Display: public virtual Link

{ // ...

};

class Device: public Task, public Display

{ // ...

};

Все части объекта Device могут использовать единственную копию Link.

Графическая схема наследования воспринимает вид:

Link

Task Display


Device

В графе наследования все виртуальные базисные классы с одним именованием будут представлены одним единственным объектом этого класса. С другой Множественное наследование классов сто­роны, каждый невиртуальный базисный класс будет иметь отдельный подобъект, представляющий его.

Программирование виртуальных базисных классов.

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

class A

{ // нет конструктора };

class B

{ public: B Множественное наследование классов(); // конструктор по дефлоту };

class С

{ public: С(int); // конструктор с параметром };

class D: public virtual A, public virtual B, public virtual C

{ D() {/*...*/} // ошибка: нет конструктора с параметром для С

D (int i):C(i) {/*...*/} // верно

};

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

Пусть есть базисный класс Window (окно), который "знает", как отрисовывать свое содержание:

class Window

{ // ...

virtual void draw(); // виртуальная функция изображения окна

};

Не считая того, есть классы с разными методами дизайна окон и до­полнительными средствами Множественное наследование классов представления данных:

class Winborder: public virtual Window // окно с рамкой

{ // код дизайна окна рамкой

void owndraw(); // показать рамку

void draw(); // замещение виртуальной функции

};

class Winmenu: public virtual Window // окно с меню

{ // код представления меню

void owndraw(); // показать меню

void draw(); // замещение виртуальной функции

};

Функции owndraw() не должны быть виртуальными, так как предпо­лагается, что они будут вызваны Множественное наследование классов из виртуальной функции draw(), которая "зна­ет" тип объекта, для которого она вызвана. Из этого можно сделать новый класс Clock (часы):

class Clock: public Winborder, public Winmenu

{ // код, описывающий часы

void owndraw(); // показать циферблат и стрелки

void draw(); // замещение виртуальной функции

};

Связи классов можно представить последующим графом:

Window

Winborder Winmenu

Clock

Виртуальные функции draw() можно написать Множественное наследование классов с внедрением функций owndraw() так, чтоб код, вызывающий всякую draw(), косвенно вызывал при всем этом Window::draw() ровно один раз независимо от типа окна:

void Winborder::draw()

{ Window::draw(); // показать окно

owndraw(); // показать рамку

};

void Winmenu::draw()

{ Window::draw(); // показать окно

owndraw(); // показать меню

};

void Clock: public Winborder::draw()

{ Window::draw(); // показать Множественное наследование классов окно

Winborder::owndraw(); // показать рамку

Winmenu::owndraw(); // показать меню

owndraw(); // показать циферблат и стрелки

};

Замещение функций виртуальных базисных классов.

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

К примеру, класс Window мог бы иметь функцию setcolor() (установить цвет) и prompt() (выдать приглашение на ввод). Тогда Winborder мог бы заме­стить функцию setcolor() для управления цветом, а Winmenu мог бы заместить функцию prompt() для взаимодействия с юзером:

class Множественное наследование классов Window // абстрактный класс

{ // ...

virtual setcolor(Color)=0;

virtual void prompt()=0;

};

class Winborder: public virtual Window

{ // ...

setcolor(Color); // управление цветом фона

};

class Winmenu: public virtual Window

{ // ...

void prompt(); // взаимодействие с юзером

};

class Mywindow: public Winborder, public Winmenu

{ // ...

};

Что если разные производные классы заместят одну и ту же функцию? Тогда если мы порождаем от этих классов новый Множественное наследование классов производный класс, мы долж­ны в нем заместить эту функцию. Другими словами, одна функция должна замещать все другие. К примеру, Mywindow мог бы заместить prompt() для улучшения интерфейса Winmenu:

class Mywindow: public Winborder, public Winmenu

{ // ...

void prompt(); // свое взаимодействие с юзером

};

В графическом виде это смотрится так:

Window { setcolor(), prompt Множественное наследование классов() }

Winborder{ setcolor()} Winmenu { prompt() }

Mywindow { prompt() }

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

Внедрение множественного наследования.

Простым и более естественным применением множественного насле­дования является "склеивание" 2-ух никаким образом не связанных класов вме­сте в качестве реализации третьего класса. Такое внедрение множественно­го наследования довольно отлично. Оно позволяет програм­мисту избе­жать написания огромного количества функций, которые Множественное наследование классов переадресу­ют вы­зовы друг дружке. Множественное наследование позволяет "братским" классам вместе использовать информацию без введения зависимости от единствен­ного общего базисного класса в программке. Это является случаем так называемо­го ромбовидного наследования (к примеру, см. выше классы Clock, My­window). Виртуальный базисный класс в противоположность обычному ба Множественное наследование классов­зовому классу требуется в тех случаях, когда базисный класс не должен повто­ряться.

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

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

Резюме.

Абстрактный класс является интерфейсом. Иерархия классов — сред­ством поочередного построения классов. Естественно, каждый класс предоставляет своим юзерам интерфейс, и Множественное наследование классов некие абстрактные клас­сы обеспечивают полезную функциональность, но, все же, "интерфейс" и "строй блоки" — вот главные роли абстрактных классов и иерархии классов. Традиционные иерархии имеют тенденцию соединять вопросы реали­зации с интерфейсами для юзера. В этих случаях на помощь приходит абстрактные классы. Иерархии абстрактных классов предоставляют ясный и мощнейший метод Множественное наследование классов выражения концепций, не загроможденных вопросами реализа­ции, и при всем этом не приводят к значимым затратным расходам. Результатом проектирования должна быть система, предоставляемая юзеру в виде иерархии абстрактных классов и реализуемая с помощью традиционной иерар­хии. Подводя результат, можно сказать, что абстрактные типы созданы для того, чтоб:

1. Найти Множественное наследование классов одно понятие таким макаром, чтоб позволить сосуществовать в программке нескольким реализациям.

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

3. Минимизировать зависимость каждой реализации от других классов.

Пример 44.

Разглядим пример построения иерархии множественного наследования классов на базе абстрактного класса. За базу возьмем пример 42 с иерархией обычного Множественное наследование классов наследования Figure<-Point<-Circle, но произведем в нем нужные конфигурации и дополним новыми классами.. Класс Figure создадим интерфейсным абстрактным базисным классом с чисто виртуальными функциями (Show, Hide), а его данные (X, Y) и функции с ними связанные (Getx, Gety) передадим в класс Point, где они кажутся более уместными, определяя положение точки. В классе Point Множественное наследование классов замещены виртуальные функции Show, Point.

Разработаем новый класс для работы с текстовым объектом Message, который резко отличается от графических объектов. К его данным относятся указатель на текст (*Msg), и характеристики текста: шифт (Font), размер поля текста (Field). В этом классе замещаются виртуальные функции Show, Hide.

Сделаем очередной класс Множественное наследование классов Msgcirc, который наследует характеристики 2-ух родительских базисных классов: Circle и Message, также замещает виртуальные функции Show, Point.

Иерархию наследования (Figure<-Point<-(Circle, Message)<-Msgcirc) можно отразить последующим графом:

Figure

Point

Circle Message

Msgcirc

Каждый класс (не считая Figure) имеет собственный конструктор.

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

#include

#include

#include

#include // для random(), kbhit()

#include // для delay()

#include

enum Boolean {false, true}; // логические значения

const char *path= "c:\\borlandc\\bgi"; // путь к функциям графики

class Figure // абстрактный интерфейсный класс

{ public:

virtual void Show Множественное наследование классов()=0; // 2 незапятнанные виртуальные функции

virtual void Hide()=0;

};

class Point: public Figure // производный класс Point

{ protected:

int X, Y; // координаты точки

Boolean Visible; // видимость точки

public:

Point (int Initx, int Inity); // конструктор Point

int Getx() { return X; } // текущий Х

int Gety() { return Y; } // текущий Y

// виртуальные способы:

void Show(); // показ точки

void Hide(); // стирание точки

// невиртуальный способ:

Boolean Isvisible() // определение Множественное наследование классов видимости точки

{ return Visible; }

};

class Circle: public Point // производный класс Circle

{ protected:

int Radius; // радиус окружности

public:

Circle (int Initx, int Inity, int Initradius); // конструктор Circle

// виртуальные способы:

void Show (); // показ окружности

void Hide(); // стирание окружности

};

class Message: public Point // производный класс Message

{ private:

char *Msg; // указатель на текст

int Font; // шрифт

int Field; // размер

public:

// конструктор:

Message Множественное наследование классов(int Msgx, int Msgy, int Msgfont, int Msgfield, char *Text);

// виртуальные способы:

void Show(); // показ текста

void Hide(); // стирание текста

};

// Производный класс от Circle и Message:

class Msgcirc: public Circle, public Message

{ public:

// конструктор:

Msgcirc(int Mcircx, int Mcircy, int Mcircrad, int Font, char *Msg);

// виртуальные способы:

void Show(); // показ текста в Множественное наследование классов окружности

void Hide(); // стирание текста и окружности

};

// Способы класса Point:

Point :: Point(int Initx, int Inity) // конструктор точки

{ X=Initx; Y=Inity; Visible = false;

}

void Point:: Show() // показ точки

{ if( ! Visible) // если точка невидима, то

{ Visible = true; // задать видимость

setcolor(RED); // цвет точки

putpixel (X, Y, getcolor() ); // изображение точки на дисплее

}

}

void Point:: Hide() // стирание точки

{ if(Visible) // если Множественное наследование классов точка видима, то

{ Visible = false; // задать невидимость точки

putpixel (X, Y, getbkcolor() ); // стирание точки цветом фона

}

}

// Способы класса Circle:

Circle::Circle (int Initx, int Inity, int Initradius): // конструктор окружности

Point(Initx, Inity) // вызов конструктора точки

{ Radius=Initradius; // исходный радиус

}

void Circle::Show() // показ окружности

{ if( ! Isvisible()) // если невидима, то

{ Visible=true; // задать видимость

circle(X, Y, Radius); // изображение Множественное наследование классов окружности

}

}

void Circle::Hide() // стирание окружности

{ int Tempcolor; // переменная цвета

Tempcolor=getcolor(); // сохранение текущего цвета

setcolor(getbkcolor()); // задать цвет фона

Visible=false; // окружность невидима

circle(X, Y, Radius); // стирание окружности фоном

setcolor(Tempcolor); // востановление текущего цвета

}

// Способы класса Message:

// конструктор Message:

Message::Message(int Msgx, int Msgy, int Msgfont, int Msgfield, char *Text):

Point(Msgx,Msgy) // вызов Множественное наследование классов конструктора точки

{ Font=Msgfont; // шрифт текста

Field=Msgfield; // размер текста

Msg=Text; // указатель на текст

}

void Message::Show() // показ теста

{ int size=Field / (8*strlen(Msg)); // размер текста (8 пикселей на знак)

settextjustify(CENTER_TEXT, CENTER_TEXT); // центр теста

settextstyle(Font, HORIZ_DIR, size); // стиль текста

outtextxy (X,Y,Msg); // вывод текста

}

void Message::Hide() // стирание текста

{ int Множественное наследование классов Tempcolor;

Tempcolor=getcolor(); // сохранение цвета

setcolor(getbkcolor()); // цвет фона

Visible=false; // текст невидим

int size=Field / (8*strlen(Msg)); // размер текста

settextjustify(CENTER_TEXT, CENTER_TEXT); // центр текста

settextstyle(Font, HORIZ_DIR, size); // стиль текста

outtextxy (X,Y,Msg); // текст цветом фона

setcolor(Tempcolor); // текущий цвет

}

// Способы класса Msgcirc:

// конструктор Msgcirc:

Msgcirc::Msgcirc(int Mcircx, int Mcircy, int Mcircrad, int Множественное наследование классов Font, char *Msg):

Circle(Mcircx,Mcircy,Mcircrad), // вызов конструкторов Circle

Message(Mcircx,Mcircy,Font,2*Mcircrad,Msg) // и Message

{ }

void Msgcirc::Show() // вывод окружности и текста

{ Circle::Show(); // вывод окружности

Message::Show(); // вывод текста

}

void Msgcirc::Hide() // стирание окружности и текста

{ Circle::Hide(); // стирание окружности

Message::Hide(); // стирание текста

}

void main() // основная функция

{ int gdriver = DETECT, gmode; // характеристики графики

initgraph Множественное наследование классов (&gdriver, &gmode, path); // инициирование графики

int col; // пременная цвета

// сделать и инициировать три объекта:

Msgcirc Small(250,100, 25, SANS_SERIF_FONT, "You");

Msgcirc Medium(250,150,100, TRIPLEX_FONT, "World");

Msgcirc Large(250, 250, 225, GOTHIC_FONT, "Universe");

while(!kbhit()) // цикл показа объектов до нажатия хоть какой кнопки

{ randomize(); // рандомизация

col = random(16); // случайный цвет

if (col == BLACK) col++; // исключение темного цвета

setcolor Множественное наследование классов(col); // текущий цвет

Small.Show(); // вывод объектов с задержкой

delay(500);

Medium.Show();

delay(500);

Large.Show();

delay(500);

Large.Hide(); // стирание объектов с задержкой

delay(500);

Medium.Hide();

delay(500);

Small.Hide();

delay(500);

}

closegraph(); // закрытие графического режима

}

ШАБЛОНЫ

В С++ предусмотрена еще одна реализация идеи полиформизма – шаблоны функций (Function Templates) и шаблоны классов (Class Templates). Подобно тому, как класс Множественное наследование классов представляет собой схематическое построение объекта (другими словами его программную модель), так и шаблон представляет схематическое описание построения функций и классов.

Исходя из убеждений проектирования шаблоны служат двум, не достаточно связанным меж собой целям:

· обобщенному программированию;

· политике параметризации.

На ранешних стадиях проектирования программного продукта операции являются просто операциями Множественное наследование классов. Потом, когда настает время обрисовать типы операндов, шаблоны приобратают гигантскую значимость. Без шаблонов определения функций стали бы повторяться. Операция, реализующая метод для операндов различных типов, является кандидатом на реализацию в виде шаблона. Если все операнды вписываются в единую иерархию классов, и если есть необходимость добавлять новые типы операндов во Множественное наследование классов время выполнения программки, тип операнда идеальнее всего представить классом – нередко абстрактным классом. Если типы операнда не вписываются в единую иерархию, и в особенности если критично быстродействие, эти операции лучше воплотить в виде шаблона.

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

Шаблоны в особенности полезны в библиотеках классов, которыми пользуются программеры. Способы, которые можно использовать при проектировании и реализации стандартной библиотеки, позволяют программеру упрятать сложную реализацию за ординарными интерфейсами. К примеру, sort(v) может служить интерфейсом для огромного количества различных алгоритмов сортировки частей разных типов, хранящихся в самых различных контейнерах Множественное наследование классов (вектор, перечень, стек и т.д.). Функция сортировки, более подходящая для определенного v, будет выбрана автоматом. Стандартная сортировка является обобщенной по типам контейнеров, так как к ней можно обращаться для случайных контейнеров, удовлетворяющих эталонам.

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

Шаблоны функций

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

template

void f (T param)

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

}

Префикс template показывает, что объявлен шаблон (template), и что в объявлении на месте Т Множественное наследование классов будет указан фактический тип, определяемой юзером функции. Т можно поменять на хоть какое другое имя. Слово class обозначает хоть какой тип данных, а не непременно класс С++. Нужен, по последней мере, один параметр типа Т в скобках для передачи функции данных для обработки. Можно задать значение (T param Множественное наследование классов), указатель (T* param) либо ссылку (T& param).

Пример 45.

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

#include

#include

// шаблон функции:

template T sqrt (T a)

{ return a*a; }

// макеты реальных функций:

int sqrt (int x);

float sqrt (float x);

long sqrt (long x Множественное наследование классов);

long double sqrt (long double x);

// основная функция:

void main ()

{ int i = 10; float f = 1.1; long l = =12345; long double ld = 12.3E12;

clrscr();

cout << "int i = " << sqrt (i) <

cout << "float f = " << sqrt (f) <

cout << "long l = " << sqrt (l) <

cout << "long double ld = " << sqrt (ld) <

getch();

}

В шаблоне можно объявлять несколько характеристик и возвращать значение типа Т, к примеру:

template T f (int a, T b)

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

}

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

double f (int a, double b);

Если б f была обыкновенной функцией, то пришлось бы обеспечить ее реализацию. Но так как Множественное наследование классов f – шаблонная функция, компилятор сам реализует код функции, заменив Т на double. Естественно, над типом, для которого будет вызыватся шаблонная функция, должны быть определены операции над переменными типа Т, которые употребляются в теле функции.

Разглядим примеры, в каких проясняется, как при помощи шаблонов можно уменьшить размер и сложность программ.

Пример 46.

Объявляется два Множественное наследование классов шаблона функций min() и max() для определения минимума либо максимума из 2-ух значений. В программке объявляются макеты реальных функций для обработки данных разных типов.

#include

#include

// шаблоны функций:

template T max (T a, T b)

{ if (a > b) return a;

return b;

}

template T min (T a, T b)

{ if (a Множественное наследование классов < b) return a;

return b;

}

// макеты реальных функций с данными различных типов:

int max (int a, int b);

double max (double a, double b);

char max (char a, char b);

int min (int a, int b);

double min (double a, double b);

char min (char a, char Множественное наследование классов b);

// основная функция:

void main()

{ int i1=100, i2=200;

double d1=3.14, d2=9.8;

char c1= 'A', c2 = 'Z';

clrscr();

cout<<"max(i1=" << i1 << ", i2=" << i2 <<"): " << max(i1, i2) <

cout<<"max(d1="<

cout<<"max(c1="<< c1<<", c2="<< c2 <<"): " << max(c1, c2) <

cout<<"min(i1=" << i1 << ", i2=" << i2 <<"): " << min(i Множественное наследование классов1, i2) <

cout<<"min(d1="<< d1<<", d2=" << d2 <<"): " << min(d1, d2) <

cout<<"min(c1="<< c1<<", c2=" << c2 <<"): " << min(c1, c2) <

getch();

}

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

max(i1=100, i2=200): 200

max(d1=3.14, d2=9.8): 9.8

max(c1=A, c2=Z): Z

min(i1=100, i2=200): 100

min(d1=3.14, d2=9.8): 3.14

min(c1=A, c2=Z): A

В Множественное наследование классов шаблоне функции можно использовать несколько характеристик и не непременно схожего типа, к примеру:

template

T1 max (T1 a, T2 b)

{ if (a > b) return a;

return b;

}

При всем этом появляется вопрос, почему возвращаемый тип Т1, а не Т2?
В С++ нет механизма конфигурации типа возвращаемого значения, потому было надо сделать Множественное наследование классов какой-нибудь выбор. Для того чтоб эти функции возвращали итог без утраты значения, при вызове функции лучше переменную либо константу "старшего" типа использовать в качестве первого параметра.

Пример 47.

Внедрение шаблона функции с 2-мя параметрами различных типов:

#include

template

T1 max (T1 a, T2 b)

{ if (a > b) return a;

return b Множественное наследование классов;

}

void main()

{ int i=5; double d=3.23; long l=123456; long double ld=1.2E123;

cout<< "max(d, i)=" << max(d, i) << endl;

cout<< "max(i, d)=" << max(i, d) << endl;

cout<< "max(ld, l)=" << max(ld, l) << endl;

// В 2-ух последующих вызовах будет неправильный итог,

// это связано не с шаблоном, а преобразованием типов Множественное наследование классов:

cout<< "max(i, l)=" << max(i, l) << endl;

cout<< "max(l, 5.5)=" << max(l, 5.5) << endl;

// А в этом вызове итог верный:

cout<< "max(5.5, l)=" << max(5.5, l) << endl;

}


mobilnaya-reklama-sms-reklama.html
mobilnie-dengi-yandeksa-otchet-soyuz-potrebitelej-finansovih-uslug-finpotrebsoyuz.html
mobilnie-telefoni-inogda-nazivaemie-sotovimi-bistro-stanovyatsya-neotemlemoj-chastyu-sovremennih-sredstv-elektrosvyazi-vnekotorih-rajonah-mira-oni-yavlyayutsya-nai.html