Класса шаблон: Шаблоны классов в С++ | Уроки С++

Содержание

Основы шаблонов С++: шаблоны функций / Хабр

Дисклаймер: статья была начата еще в феврале, но, по зависящим от меня причинам, закончена не была. Тема очень обширна, поэтому публикуется в урезанном виде. Что не поместилось, будет рассмотрено позже.

Невозможно разбираться в современном С++, не зная, что такое шаблоны программирования. Данное свойство языка открывает широкие возможности оптимизации и повторного использования кода. В данной статье попробуем разобраться, что это такое и как это всё работает.

Механизм шаблонов в языке С++ позволяет решать проблему унификации алгоритма для различных типов: нет необходимости писать различные функции для целочисленных, действительных или пользовательских типов – достаточно составить обобщенный алгоритм, не зависящий от типа данных, основывающийся только на общих свойствах. Например, алгоритм сортировки может работать как с целыми числами, так и с объектами типа «автомобиль».

Существуют шаблоны функций и шаблоны классов.

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

Шаблоны классов -– обобщенное описание пользовательского типа, в котором могут быть параметризованы атрибуты и операции типа. Представляют собой конструкции, по которым могут быть сгенерированы действительные классы путём подстановки вместо параметров конкретных аргументов.

Рассмотрим более подробно шаблоны функций.

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


Как написать первую шаблонную функцию?

Рассмотрим случай определения минимального элемента из двух. В случае целых и действительных чисел придется написать 2 функции.
int _min(int a, int b){
    if( a < b){
        return a;
    }
    return b;
}

double _min(double a, double b){
    if( a < b){
        return a;
    }
    return b;
}

Можно, конечно, реализовать только одну функцию, с действительными параметрами, но для понимания шаблонов это будет вредным.
Что произойдёт в случае компиляции приложения? Обе реализации функции попадут в бинарный код приложения, даже если они не используются (впрочем, сейчас компиляторы очень умные, умеют вырезать неиспользуемый код). А если необходимо добавить функцию, определяющую минимальную из 2 строк (сложно представить без уточнения, что есть минимальная строка)?!

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

  1. берётся реализация функции для какого-то типа;
  2. приписывается заголовок template<class Type> (или template<typename Type>), что означает, что в алгоритме используется какой-то абстрактный тип Type;
  3. в реализации функции имя типа заменяется на Type.

Для функции min получится следующее:
template<class Type>
Type _min(Type a, Type b){
    if( a < b){
        return a;
    }
    return b;
}

Самым интересным является тот факт, что пока нет вызова функции min, при компиляции она в бинарном коде не создается (не инстанцируется). А если объявить группу вызовов функции с переменными различных типов, то для каждого компилятор создаст свою реализацию на основе шаблона.

Вызов шаблонной функции, в общем, эквивалентен вызову обыкновенной функции. В этом случае компилятор определит, какой тип использовать вместо Type, на основании типа фактических параметров. Но если подставляемые параметры окажутся разных типов, то компилятор не сможет вывести (инстанцировать шаблон) реализацию шаблона. Так, в ниже следующем коде компилятор споткнётся на третьем вызове, так как не может определить, чему равен Type (подумайте, почему?):

#include <iostream>
template<class Type>
Type _min(Type a, Type b) {
    if (a < b) {
        return a;
    }
    return b;
}

int main(int argc, char** argv) {
    std::cout << _min(1, 2) << std::endl;
    std::cout << _min(3.1, 1.2) << std::endl;
    std::cout << _min(5, 2.1) << std::endl; // oops!
    return 0;
}

Решается эта проблема указанием конкретного типа при вызове функции.
#include <iostream>
template<class Type>
Type _min(Type a, Type b) {
    if (a < b) {
        return a;
    }
    return b;
}

int main(int argc, char** argv) {
    std::cout << _min<double>(5, 2.1) << std::endl;
    return 0;
}

Когда шаблонная функция (не) будет работать?

В принципе, можно понять, что компилятор просто подставляет нужный тип в шаблон. Но всегда ли получаемая функция будет работоспособна? Очевидно, что нет. Любой алгоритм может быть определен независимо от типа данных, но он обязательно пользуется свойствами этих данных. В случае с шаблонной функцией _min это требование определения оператора упорядочения (оператор

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

Перегрузка шаблона функции

Шаблоны функций также могут перегружаться. Обычно данная перегрузка выполняется при
template<class Type>
Type* _min(Type* a, Type* b){
    if(*a < *b){
        return a;
    }
    return b;
}

Частные случаи

В некоторых случаях шаблон функции является неэффективным или неправильным для определенного типа. В этом случае можно специализировать шаблон, — то есть написать реализацию для данного типа. Например, в случае со строками можно потребовать, чтобы функция сравнивала только количество символов. В случае специализации шаблона функции тип, для которого уточняется шаблон в параметре не указывается. Ниже приводится пример указанной специализации.
template<>
std::string _min(std::string a, std::string b){
    if(a.size() < b.size()){
        return a;
    }
    return b;
}

Специализация шаблона для конкретных типов делается опять же из соображения экономичности: если эта версия шаблона функции в коде не используется, то она не будет включена в бинарный код.
На будущее остаются множественные и целочисленные параметры. Естественным продолжением являются шаблоны классов, основы порождающего программирования, и устройство стандартной библиотеки С++. И куча примеров!

Шаблоны и шаблонные функции в C++. Введение

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

Давайте рассмотрим простой пример. Допустим, у нас есть функция, которая меняет местами значения двух переменных типа int:

#include <iostream>

void my_swap ( int & first , int & second )
{
    int temp ( first ) ;
    first = second ;
    second = temp ;
}

int main ()
{
    int a = 5 ; 
    int b = 10 ;
    std::cout << a << " " << b << std::endl ;
    my_swap ( a , b ) ;
    std::cout << a << " " << b << std::endl ;
}

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

void my_swap ( double & first , double & second )
{
    double temp ( first ) ;
    first = second ;
    second = temp ;
}

И теперь перепишем main:

int main ()
{
    int a = 5 ; 
    int b = 10 ;
    std::cout << a << " " << b << std::endl ;
    my_swap ( a , b ) ;
    std::cout << a << " " << b << std::endl ;
    double c = 77.89 ;
    double d = 54.22 ;
    std::cout << c << " " << d << std::endl ;
    my_swap ( c , d ) ;
    std::cout << c << " " << d << std::endl ;
}

Как видите, у нас алгоритм абсолютно одинаковый, отличаются лишь типы параметров и тип переменной temp. А теперь представьте, что нам еще нужны функции для short, long double, char, string и еще множества других типов. Конечно, можно просто скопировать первую функцию, и исправить типы на нужные, тогда получим новую функцию с необходимыми типами. А если функция будет не такая простая? А вдруг потом еще обнаружится, что в первой функции была ошибка? Избежать всего этого можно, например, «шаманством» с препроцессором, но это нам ни к чему, нам помогут шаблоны.

Для начала, заглянем в википедию и посмотрим, что же такое шаблоны:

Шабло́ны (англ. template) — средство языка C++, предназначенное для кодирования обобщённых алгоритмов, без привязки к некоторым параметрам (например, типам данных, размерам буферов, значениям по умолчанию).
https://ru.wikipedia.org/wiki/Шаблоны_C++

Итак, описание шаблона начинается с ключевого слова template за которым в угловых скобках («<» и «>») следует список параметров шаблона. Далее, собственно идет объявление шаблонной сущности (например функция или класс), т. е. имеет вид:

template < template-parameter-list > declaration.

Теперь давайте напишем шаблонную функцию my_swap. Исходя из упомянутой выше структуры объявления шаблона следует, что наша функция будет выглядеть так: template < параметры_шаблона > описание_функции.

Напишем функцию:

template < typename T >
void my_swap ( T & first , T & second )
{
    T temp(first) ;
    first = second ;
    second = temp ;
}

typename в угловых скобках означает, что параметром шаблона будет тип данных. T — имя параметра шаблона. Вместо typename здесь можно использовать слово class: template < class T > В данном контексте ключевые слова typename и class эквивалентны (лично мне больше нравится typename, а кому-то class). Далее, в тексте шаблона везде, где мы используем тип T, вместо T будет проставляться необходимый нам тип.

void my_swap ( T & first , T & second ) //T - тип, указанный в параметре шаблона
{
    T temp(first) ; //временная переменная должна быть того же типа, что и параметры
    first = second ;
    second = temp ;
}

теперь давайте напишем функцию main:

int main ()
{
    int a = 5 ; 
    int b = 10 ;
    std::cout << a << " " << b << std::endl ;
    my_swap<int> ( a , b ) ;
    std::cout << a << " " << b << std::endl ;
    double c = 77.89 ;
    double d = 54.22 ;
    std::cout << c << " " << d << std::endl ;
    my_swap<double> ( c , d ) ;
    std::cout << c << " " << d << std::endl ;
}

Как видите, после имени функции в угловых скобках мы указываем тип, который нам необходим, он то и будет типом T. Шаблон — это лишь макет, по которому компилятор самостоятельно будет генерировать код. При виде такой конструкции:

my_swap<тип> компилятор сам создаст функцию my_swap с необходимым типом. Это называется инстанцирование шаблона. То есть при виде my_swap<int> компилятор создаст функцию my_swap в которой T поменяет на int, а при виде my_swap<double> будет создана функция с типом double. Если где-то дальше компилятор опять встретит my_swap<int>, то он ничего генерировать не будет, т.к. код данной функции уже есть(шаблон с данным параметром уже инстанцирован).

Таким образом, если мы инстанцируем этот шаблон три раза с разными типами, то компилятор создаст три разные функции

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

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

рассмотрим вызов функции без указания типа:

int a = 5 ;
int b = 10 ;
my_swap ( a , b ) ;

Наша шаблонная функция принимает параметры типа T&, основываясь на шаблоне, компилятор видит, что Вы передаете в функцию аргументы типа int, поэтому может самостоятельно определить, что в данном месте имеется ввиду функция my_swap с типом int. Это deducing template arguments. Теперь давайте напишем пример посложнее. Например, программу сортировки массива(будем использовать сортировку «пузырьком»). Естественно, что алгоритм сортировки один и тот же, а вот типы элементов в массиве будут отличаться. Для обменивания значений будем использовать нашу шаблонную функцию my_swap. Приступим:

#include <iostream>

template < typename T >
void my_swap ( T & first , T & second ) //T - тип, указанный в параметре шаблона
{
    T temp(first) ; //временная переменная должна быть того же типа, что и параметры
    first = second ;
    second = temp ;
}

//Функция будет принимать указатель на данные 
//и кол-во элементов массива данных
//Сам алгоритм сортировки можете посмотреть в Интернете.
//Никаких оптимизаций и проверок аргументов применять не будем, нам нужна просто демонстрация.    
template < class ElementType > //Использовал class, но можно и typename - без разницы
void bubbleSort(ElementType * arr, size_t arrSize)
{
    for(size_t i = 0; i < arrSize - 1; ++i) 
        for(size_t j = 0; j < arrSize - 1; ++j)
            if (arr[j + 1] < arr[j]) 
                my_swap ( arr[j] , arr[j+1] ) ;
}

template < typename ElementType >
void out_array ( const ElementType * arr , size_t arrSize )
{
    for ( size_t i = 0 ; i < arrSize ; ++i )
       std::cout << arr[i] << ' ' ;
    std::cout << std::endl ;
}


int main ()
{
    const size_t n = 5 ;
    int arr1 [ n ] = { 10 , 5 , 7 , 3 , 4 } ;
    double arr2 [ n ] = { 7.62 , 5.56 , 38.0 , 56.0 , 9.0 } ;
    std::cout << "Source arrays:\n" ;
    out_array ( arr1 , n ) ;//Компилятор сам выведет параметр шаблона исходя из первого аргумента функции
    out_array ( arr2 , n ) ;

    bubbleSort ( arr1 , n ) ;
    bubbleSort ( arr2 , n ) ;

    std::cout << "Sorted arrays:\n" ;
    out_array ( arr1 , n ) ;
    out_array ( arr2 , n ) ;
}

Вывод программы:

Source arrays: 10 5 7 3 4 7.62 5.56 38 56 9 Sorted arrays: 3 4 5 7 10 5.56 7.62 9 38 56

Как видите, компилятор сам генерирует out_array для необходимого типа. Так же он сам генерирует функцию bubbleSort. А в bubbleSort у нас применяется шаблонная функция my_swap, компилятор сгенерирует и её код автоматически. Удобно, не правда ли?

Введение в шаблонные классы

Шаблонными могут быть не только функции. Рассмотрим шаблонные классы. Начнем с простого примера. Мы добавим в наш предыдущий код функцию, которая будет искать максимум и минимум в массиве. При создании функции «упираемся» в проблему — как вернуть два указателя? Можно передать их в функцию в качестве параметров, а можно вернуть объект, который будет содержать в себе два указателя. Первый вариант при большом кол-ве возвращаемых значений приведет к заваливанию функции параметрами, поэтому я предлагаю сделать структуру:

struct my_pointer_pair
{
   тип * first ;
   тип * second ;
} ;

А какого же типа будут указатели? Можно сделать их void*, но тогда придется постоянно кастовать их к нужному типу, и код станет похож на «Доширак». А что, если сделать эту структуру шаблонной? Попробуем:

template < typename T, typename U >
struct my_pointer_pair
{
   T * first ;
   U * second ;
}  ;

Теперь компилятор при виде кода my_pointer_pair<тип1,тип2> сам сгенерирует нам код структуры с соответствующими типами. В данном примере указатели у нас будут одинакового типа, но структуру мы сделаем такой, чтобы типы указателей могли быть разными. Это может быть полезно в других примерах (в данном случае я просто хотел показать, что у шаблона может быть не только один параметр).

int main ()
{
    my_pointer_pair<int,double> obj = { new int(10) , new double(67.98) } ;//Создаем объект типа my_pointer_pair<int,double>
    std::cout << *obj.first << ' ' << *obj.second << std::endl ;
    delete obj.first ;
    delete obj.second ;
}

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

Теперь давайте напишем код шаблонной функции для поиска максимума и минимума:

//Шаблон наш будет с одним параметром - тип элементов массива (T)
//Возвращаемое значение - объект типа my_pointer_pair< T , T >
//т.е. first и second в my_pointer_pair будут иметь тип T*.
template < typename T >
my_pointer_pair< T , T > my_minmax_elements (  T * arr , size_t arrSize )
{
    my_pointer_pair< T , T > result = { 0 , 0 } ;
    if ( arr == 0 || arrSize < 1 )
         return result ;
    result.first = arr ;
    result.second = arr ;
    for ( size_t i = 1 ; i < arrSize ; ++i )
    {
        if ( arr[i] < *result.first )
            result.first = arr+i ;
        if ( arr[i] > *result.second )
           result.second = arr+i ;
    }
    return result ;
}

Теперь мы можем вызывать данную функцию:

my_pointer_pair< int , int > mm = my_minmax_elements ( arr1 , n ) ;

Для классов мы должны явно указывать параметры шаблона. В стандарте C++11, устаревшее ключевое слово auto поменяло свое значение и теперь служит для автоматического вывода типа в зависимости от типа инициализатора, поэтому мы можем написать так:

auto mm = my_minmax_elements ( arr1 , n ) ;

Предлагаю написать еще одну функцию, которая будет выводить объект my_pointer_pair в стандартный поток вывода:

template < typename T1 , typename T2 >
void out_pair ( const my_pointer_pair< T1 , T2 > & mp )
{
    if ( mp.first == 0 || mp.second == 0 )
        std::cout << "not found" << std::endl ;
    else
        std::cout << "min = " << *mp.first << " max = " << *mp.second << std::endl ;
}

Теперь соберем всё воедино:

#include <iostream>


template < typename ElementType >
void out_array ( const ElementType * arr , size_t arrSize )
{
    for ( size_t i = 0 ; i < arrSize ; ++i )
       std::cout << arr[i] << ' ' ;
    std::cout << std::endl ;
}


template < typename T, typename U >
struct my_pointer_pair
{
   T * first ;
   U * second ;
}  ;


//Шаблон наш будет с одним параметром - тип элементов массива (T)
//Возвращаемое значение - объект типа my_pointer_pair< T , T >
//т.е. first и second в my_pointer_pair будут иметь тип T*.
template < typename T >
my_pointer_pair< T , T > my_minmax_elements (  T * arr , size_t arrSize )
{
    my_pointer_pair< T , T > result = { 0 , 0 } ;
    if ( arr == 0 || arrSize < 1 )
         return result ;
    result.first = arr ;
    result.second = arr ;
    for ( size_t i = 1 ; i < arrSize ; ++i )
    {
        if ( arr[i] < *result.first )
            result.first = arr+i ;
        if ( arr[i] > *result.second )
           result.second = arr+i ;
    }
    return result ;
}

template < typename T >
void out_pair ( const my_pointer_pair< T , T > & mp )
{
    if ( mp.first == 0 || mp.second == 0 )
        std::cout << "not found" << std::endl ;
    else
        std::cout << "min = " << *mp.first << " max = " << *mp.second << std::endl ;
}

int main ()
{
    const size_t n = 5 ;
    int arr1 [ n ] = { 10 , 5 , 7 , 3 , 4 } ;
    double arr2 [ n ] = { 7.62 , 5.56 , 38.0 , 56.0 , 9.0 } ;
    std::cout << "Arrays:\n" ;
    out_array ( arr1 , n ) ;//Компилятор сам выведет параметр шаблона исходя из первого аргумента функии
    out_array ( arr2 , n ) ;

    out_pair ( my_minmax_elements ( arr1 , n ) ) ;
    out_pair ( my_minmax_elements ( arr2 , n ) ) ;
}

Вывод программы:

Arrays: 10 5 7 3 4 7.62 5.56 38 56 9 min = 3 max = 10 min = 5.56 max = 56

Шаблоны и STL

В комплекте с компилятором Вам предоставляется стандартная библиотека шаблонов (Standart Template Library). Она содержит множество шаблонных функций и классов. Например, класс двусвязного списка(list), класс «пара» (pair), функция обмена двух переменных(swap), функции сортировок, динамически расширяемый массив(vector) и т.д. Всё это — шаблоны и Вы можете их использовать. Для небольшого примера возьмем std::vector:

#include <vector>
#include <algorithm>
#include <iostream>

int main ()
{
    std::vector <int> arr;
    arr.push_back ( 5 ) ; //Добавляем элемент в конец
    arr.push_back ( 7 ) ;
    arr.push_back ( 3 ) ;
    arr.push_back ( 8 ) ;
    std::cout << "Source vector:\n" ;
    for ( size_t i = 0 , size = arr.size() ; i < size ; ++i )
        std::cout << arr[i] << ' ' ;
    std::cout << std::endl ;

    std::sort ( arr.begin() , arr.end() ) ; //Сортируем вектор

    std::cout << "Sorted vector:\n" ;
    for ( size_t i = 0 , size = arr.size() ; i < size ; ++i )
        std::cout << arr[i] << ' ' ;
   std::cout << std::endl ;
}

Заметьте, когда писали std::vector, авторы понятия не имели, элементы какого типа Вы будете хранить.

Шаблоны это слишком большой и мощный инструмент и описать всё в одной статье не представляется возможным. Это было лишь небольшое введение в мир шаблонов. Углубляясь в шаблоны, Вы поразитесь тому, какой мощный это инструмент и какие возможности он предоставляет.

P.S. высказывайте мнение о статье, критику, дополнения/исправления и интересующие вопросы в комментариях.

P.P.S. Просьба вопросы «консоль закрывается, что делать?», «русский язык не показывает. Что делать?», «как работает сортировка?», «что такое size_t», «что такое std::» и им подобные задавать либо в гугл, либо искать на данном сайте в других статьях. Не нужно захламлять комментарии этой чепухой. Если Вы этого не знаете, то может лучше сначала подтянуть свои знания?

Продолжение: Шаблоны в C++ — часть 2.

Шаблоны для оформления классного уголка




Староста – АЛИЕВА ХАВА

— Выполняет поручения классного руководителя, связанные с учебой и хозяйственной

деятельностью.

— Контролирует работу всего актива

— Изучает с учениками класса «Правила для учащихся», настойчиво добивается их выполнения.

— Следит за соблюдением дисциплины во время перемен.

Помощник старосты — РАСУЛОВА АЙШАТ

— Замещает старосту в её отсутствие.

— Контролирует работу всего актива.

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

— Следит за оформлением класса на время проведения мероприятий.

Учебный секторМуртузова Самира, Джамалуева Линда, Шуайпов Рамазан

— Организуют рейды по проверке выполнения домашних заданий.

— Ежедневно контролируют подготовку класса к уроку (На парте должны находиться дневник, учебник, тетрадь, письменные принадлежности).

— Оказывают помощь отстающим учащимся.

— Контролируют выставление оценок в дневник.

Редколлегия Амитов Руслан.

-Оформляют и занимаются обновлением рубрики классного уголка.


Физорги Хаджимурадов Д, Умаров Я.

— Организуют работу по приобщению учащихся класса к спорту.

— Организуют работу по рекламе здорового образа жизни.

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

ХозяюшкаАлхуватова Зайнаб, Абдухаликова Шахрузат

— Организует дежурство по классу и контролирует его.

— Следит за состоянием школьной классной мебели.

— Следит за цветами в кабинете.

 
 Книголюбы Шуайпов Рамазан, Дибиров Ахмед.

— Проверяют состояние учебников, наличие закладок.

— Следят за ведением читательского дневника.


дежурство класса

Понедельник

Вторник

Среда

1

Алиева Х.

Асланова В.

Дибиров А.

2

Абдулаева С.

Гусейнова Р.

Исмаилов И.

3

Абдулхаликова Ш

Гамзатов С.

Магомедов Р.

4

Алхуватова З.

Гайирбекова У.

Магомедова Н.

5

Амитов Р.

Джамалуев А.

Магомедов Ю.

6

Джамалуева Л.

Четверг

Пятница

Суббота

1

Муртузова С.

Пезулаев Т.

Умаров Я.

2

М-расулова А.

Расулова А.

Хаджимурадов Д.

3

Мамаев С.

Султанов А.

Х-мурадова А.

4

Муслимов Х.

Саидбегов М.

Шуайпов Р.


Понедельник

Вторник

Среда

1

История

Русский язык

Математика

2

Математика

Математика

Физкультура

3

Физкультура

Родной язык

Русский язык

4

Физика

Русский язык

Физика

5

Родной язвк

Английский язык

Английский язык

6

Литература

География

Технология

Четверг

Пятница

Суббота

1

Математика

Русский язык

Русский язык

2

Русский язык

Математика

Литература

3

Родной язык

Английский язык

История

4

Биология

Музыка

Биология

5

География

ИЗО

Обществознание

6

Классный час

\

Технология

Физкультура



Список класса

Шаблон для оформления классного уголка



  • Не дерись без обиды, не обижайся без дела.

  • Сам ни к кому не приставай.

  • Зовут играть — иди, не зовут — попроси, это не стыдно.

  • Играй честно.

  • Не дразнись, не выпрашивай ничего; никого два раза ни о чём не проси.

  • Всегда делай уроки, из-за отметки не плачь, будь гордым.

  • С учителем не спорь и на учителя не обижайся.

  • Не ябедничай на товарищей.

  • Будь опрятным и аккуратным, окружающие грязнуль не любят.

  • Чаще говори: давай дружить, давай играть вместе.

  • Будь добр и вежлив по отношению к окружающим.


Староста класса

Руководит делами класса, следит за дисциплиной и посещаемостью, отвечает за порядок в классе, дежурство.

Художник

Помогает педагогам в оформлении класса.

Цветовод

Забота о растениях класса

Физорг

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

Хозяйственная служба класса

Отвечает за сохранность и ремонт мебели класса.

Библиотечная служба класса

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

Наш девиз:

«Пусть искорка дружбы, что вместе зажжем, подарит нам радость, согреет теплом».



Фалилия Имя –дата рождения

Фалилия Имя –дата рождения

Фалилия Имя –дата рождения

Фалилия Имя –дата рождения

Фалилия Имя –дата рождения



  1. Помогай товарищу, если умеешь что-то делать лучше, научи и его.

  2. Делись с товарищами, если у тебя есть интересные книги или игрушки.

  3. Останови товарища, если он делает что-то плохое. Если друг в чём-то не прав, скажи ему об этом.

  4. Не ссорься с ребятами, старайся работать и играть с ними дружно.

  5. Не зазнавайся, если у тебя что-то хорошо получается. Не завидуй товарищам — надо радоваться их успехам.

  6. Если поступил плохо, не стесняйся в этом признаться и исправиться.

  7. Умей принять помощь, советы и замечания от других ребят.


7.00

Подъем.

7.00 – 7.15

Водные процедуры, утренняя зарядка.

7.15– 7.30

Уборка комнаты.

7.30 – 8.00

Завтрак.

8.00 – 8.30

Прогулка, подготовка к урокам.

8.30

Начало уроков.

8.30 – 13.00

Уроки.

13.00 –13.30

Обед.

13.30 – 14.00

Прогулка перед тихим часом.

14.00 – 16.00

Тихий час.

16.10 – 16.30

Полдник.

17.00 -18.30

Самоподготовка.

Внеклассное занятие.

18.30 – 19.00

Подвижные игры на свежем воздухе.

19.00 – 19.30

Ужин.

19.30 – 20.30

Оздоровительная прогулка перед сном, тихие игры, просмотр телепередач, занятия по интересам.

20.30 – 21.00

Подготовка ко сну,

вечерний туалет. Сон.



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

Речь идет о божьей коровке. Известно ли было людям о том, какую пользу приносят им божьи коровки, сказать трудно. Но, видимо, относились к ним хорошо. Недаром же в России жучка этого издавна ласково называли «солнышко». Может быть, это — отголоски древнеславянских верований, может быть, просто потому, что он красный и кругленький.

Впрочем, не все божьи коровки красные — бывают и желтые божьи коровки, и синие (у этих точечки на надкрыльях красные).

И точек тоже может быть разное количество — и две, и пять, и тринадцать, и четырнадцать. Но чаще всего встречаются красные божьи коровки с семью точками на надкрыльях. Но какого бы цвета они ни были, их всегда можно узнать по характерной «фигуре» и капелькам жидкости, которые появляются у испугавшихся или почувствовавших опасность жучков на сгибах ножек. В народе эту жидкость называют «молочком», поэтому и прозвали жучков коровками. А «божьими» в старину называли добрых, безобидных людей. Жучок действительно на вид очень добродушный, безобидный. Так оно и есть — никому он не опасен, кроме тлей.


Это, пожалуй, самые знакомые нам птицы. И наиболее нуждающиеся в нашей помощи. Многие считают, что птицы получили свои имена за цвет перьев (синицы — значит «синие»). На самом же деле синих тонов в оперении синиц нет. Птицы издают довольно громкий мелодичный посвист — «сии-сии». Вот и назвали их синицами. Самая крупная из живущих у нас синиц — большая. По сравнению со своими сестрами действительно большая, по сравнению с другими птицами не такая уж крупная (весит граммов 20). Ее, пожалуй, чаще других можно видеть зимой в городах и селениях. Прилетает птица к людям не от хорошей жизни: трудно, голодно в лесу в это время.

В это время синицы становятся в полном смысле всеядными птицами: поедают крошки и крупу, кусочки мяса и сала. И все-таки много птиц гибнет в это время: из 10 синиц до весны в лучшем случае доживают 1-2. Гибнут не от холода, а именно от голода. Голодная птица не переносит даже слабых морозов. Но если синичка переживет зиму, уже ранней весной начнет подыскивать место для гнезда — дупло или другое подходящее укрытое место. Синицы — родители многодетные: 10-14 птенцов в гнезде не редкость. Конечно, чтобы прокормить такую семью, родителям приходится раз по 400 в день прилетать к гнезду с кормом — насекомыми. Это продолжается две недели. Подросших птенцов родители еще докармливают, когда они вылезают из гнезда. Правда, иногда это приходится делать одному папаше — самка в это время сидит уже на яйцах второй кладки. Потом две недели колоссального труда — выкармливание птенцов в гнезде, потом — докармливание… Неудивительно, что пара синиц, вместе с выводками, конечно (а в двух выводках бывает и 20 и 30 птиц), могут надежно охранять от вредителей сад в 40 фруктовых деревьев. И если ты зимой будешь подкармливать птиц, будь уверен: летом они отблагодарят тебя!

Ровно десять школьных правил

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

Изучать, запоминать

И конечно выполнять!

Не кричи, покинув класс – это раз!

И не бегай никогда – это два!

Чужие вещи не бери – это три!

А четыре – это так – пусть не будет в школе драк!

Малышей не обижать – это пять!

А конфету хочешь съесть –

Не бросай бумажку – шесть!

Семь! К обеду не бежать,

А за учителем шагать!

В коридорах мы вас просим

Поберечь растенья – восемь!

Девять! Взрослый на пути –

Слово «Здравствуйте» говори!

Десять! Прозвенел звонок

Все спешите на урок!



  1. Приучи себя мыть руки, лицо и шею каждое утро и каждый вечер перед тем,

как ложиться спать.

  1. Когда моешь руки, потри щёткой кончики пальцев, чтобы вычистить грязь из-под ногтей.

  2. Ноги мой перед сном каждый день.

  3. Чисти зубы утром и на ночь.

  4. Принимай горячий душ или ходи в баню не реже, чем раз в неделю. Горячая вода промывает от пыли и пота поры, которыми дышит наша кожа.

  5. Вернувшись с улицы, обязательно мой руки.

  6. Научись сам следить за ногтями и стричь их.

  7. Ежедневно расчесывай волосы, если длинные — то заплетай их.



Понедельник

Вторник

Среда

  1. Чтение

  1. Чтение

  1. Письмо

  1. Письмо

  1. Математика

  1. Математика

  1. Математика

  1. Письмо

  1. Чтение

  1. Труд

  1. Развитие уст.р.

  1. Музыка

  1. ЛФК

  1. Физкультура

  1. Труд

Классный час

Психомоторика

Четверг

Пятница

Суббота

  1. Письмо

  1. Письмо

  1. Математика

  1. Математика

  1. Математика

  1. Письмо

  1. Чтение

  1. Физкультура

  1. ИЗО

  1. Развитие уст.р.

  1. Чтение

  1. Труд

Психомоторика

  1. Труд

Ритмика


Шаблоны классного уголка — Шаблоны презентаций

Шаблоны классных уголков

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

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

Скачайте шаблоны оформления классного уголка

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

  • расписание звонков,
  • расписание уроков,
  • расписание кружков,
  • состав класса,
  • актив класса,
  • наши достижения,
  • наши планы,
  • график дежурств,
  • день рождения,
  • праздники.

В каждом архиве классного уголка 11 листов-шаблонов формата А4 (книжной и альбомной ориентации), которые вы можете распечатать на цветном принтере или салоне печати. Они позволят вам оформить свой кабинет без большого труда.

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

Как пользоваться шаблонами?

Если у вас нет графического редактора, рекомендуем установить листы шаблона в качестве фона презентации PowerPoint и вписать все данные. Затем сохранить презентацию и распечатать ее. Чтобы распечатать ее в салоне связи, сохраните презентацию в формате изображений JPG (Файл — Сохранить как… — JPG).

Актив класса картинки

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

Актив класса в рамке.

Для стены.

Актив класса на 1 полугодие.

Изображение для школы.

Для оформления.

Для оформления презентации.

Гордость нашего класса.

Актив класса. Учебный сектор, староста, спортивный сектор, творческая группа.

Для списка.

Оформления актива класса.

Дизайнерские шаблоны фотокниг: Групповые виньетки


Групповой коллаж «Новогодний детсад»

Шаблон для детского садика А4 формата

Групповая виньетка для садика «Мультики»


Военный коллаж для класса

Общая виньетка на 23 февраля или День Победы

Портреты для школьников и детсада «Осень золотая»

Групповое фото «В первый раз, в 1 класс»


Весенняя виньетка для детского сада «Сказочный лес»
Многослойный шаблон виньетки формата А4, 300 dpi

Весенняя виньетка для детского сада «Сказочный лес-2»
Многослойный шаблон виньетки формата А4, 300 dpi

Дружный класс
Многослойный шаблон виньетки формата А4, 300 dpi


Ноутбук
Многослойный шаблон виньетки формата А4, 300 dpi

Транспорт
Многослойный шаблон виньетки формата А4, 300 dpi


Лего
Многослойный шаблон виньетки формата А4, 300 dpi

Групповая виньетка «Клетка»
Виньетка Миньоны
Многослойный шаблон виньетки формата А4, 300 dpi
Дружный класс-2
Многослойный шаблон виньетки формата А4, 300 dpi

Виньетка Дикие птички (Angry birds)
Многослойный шаблон виньетки формата А4, 300 dpi


Школьные предметы

Многослойный шаблон виньетки формата А4, 300 dpi


Средиземноморье
Многослойный шаблон виньетки формата А4, 300 dpi

Тетрадка
Многослойный шаблон виньетки формата А4, 300 dpi

Виньетка «Диско»
Многослойный шаблон виньетки формата А4, 300 dpi

Виньетка Гламур
Многослойный шаблон виньетки формата А4, 300 dpi

Виньетка «Соты»
Многослойный шаблон виньетки формата А4, 300 dpi

Шаблон для учителя и ребенка «Школьный дуэт»
Многослойный шаблон виньетки формата А4, 300 dpi

Групповой шаблон «Чемпионат мира по футболу 2018»


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

— cppreference.com

Шаблон класса определяет семейство классов.

[править] Синтаксис

шаблон < список параметров > объявление класса (1)
экспорт шаблон < список параметров > объявление класса (2) (до C ++ 11)

[править] Пояснение

экспорт был необязательным модификатором, который объявлял шаблон как экспортированный (при использовании с шаблоном класса он также объявлял все его члены экспортированными).Файлы, которые создают экземпляры экспортированных шаблонов, не должны включать их определения: достаточно объявления. Реализации export были редкими и не согласовывались друг с другом по деталям. (до C ++ 11)

[править] Создание экземпляра шаблона класса

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

[править] Явное создание экземпляра
шаблон имя шаблона ключа класса < список аргументов > ; (1)
extern шаблон имя шаблона ключа класса < список аргументов > ; (2) (начиная с C ++ 11)
класс-ключ класс , структура или соединение

1) Явное определение экземпляра

2) Явное объявление экземпляра

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

Явное объявление создания экземпляра (шаблон extern) пропускает этап неявного создания экземпляра: код, который в противном случае вызвал бы неявное создание экземпляра, вместо этого использует явное определение экземпляра, предоставленное в другом месте (что приводит к ошибкам ссылки, если такое создание экземпляра не существует).Это можно использовать для сокращения времени компиляции путем явного объявления экземпляра шаблона во всех, кроме одного из исходных файлов, использующих его, и явного определения его в оставшемся файле.

(начиная с C ++ 11)

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

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

 пространство имен N
{
  шаблон <класс T>
  class Y // определение шаблона
  {
    void mf () {}
  };
}
// шаблон class Y ; // ошибка: шаблон класса Y не отображается в глобальном пространстве имен
используя N :: Y;
// шаблонный класс Y ; // ошибка: явное создание экземпляра вне
                          // пространства имен шаблона
шаблонный класс N :: Y ; // ОК: явное создание экземпляра
шаблон void N :: Y <двойной> :: mf (); // ОК: явное создание экземпляра 

Явное создание экземпляра не имеет эффекта, если явная специализация появилась раньше для того же набора аргументов шаблона.

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

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

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

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

[править] Неявное создание экземпляра

Когда код ссылается на шаблон в контексте, который требует полностью определенного типа, или когда полнота типа влияет на код, и этот конкретный тип не был создан явно, происходит неявное создание экземпляра. Например, когда создается объект этого типа, но не когда создается указатель на этот тип.

Это применимо к членам шаблона класса: если член не используется в программе, он не создается и не требует определения.

 шаблон <класс T>
struct Z // определение шаблона
{
    void f () {}
    void g (); // никогда не определялся
};
шаблонная структура Z <двойной>; // явное создание экземпляра Z 
Z  a; // неявное создание экземпляра Z 
Z  * p; // здесь ничего не создается
p-> f (); // здесь происходит неявное создание экземпляров Z  и Z  :: f ().
// Z  :: g () никогда не требуется и никогда не создается: его не нужно определять 

Если шаблон класса был объявлен, но не определен, в момент создания экземпляра создается экземпляр неполного типа:

 шаблон <класс T>
класс X; // объявление, а не определение

X  ch; // ошибка: неполный тип X  
Локальные классы и любые шаблоны, используемые в их членах, создаются как часть создания экземпляра объекта, в котором объявляется локальный класс или перечисление. (начиная с C ++ 17)

[править] См. Также

.

13.3 — Шаблонные классы | Изучите C ++

В предыдущих двух уроках вы узнаете, как 13.1 — шаблоны функций, экземпляры которых создаются в 13.2 — экземплярах шаблонов функций, позволяют нам обобщать функции для работы с множеством различных типов данных. Хотя это отличное начало на пути к общему программированию, оно не решает всех наших проблем. Давайте рассмотрим пример одной из таких проблем и посмотрим, что шаблоны могут в дальнейшем сделать для нас.

Шаблоны и классы контейнеров

В уроке по 10.6 — Контейнерные классы, вы узнали, как использовать композицию для реализации классов, содержащих несколько экземпляров других классов. В качестве одного из примеров такого контейнера мы рассмотрели класс IntArray. Вот упрощенный пример этого класса:

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

30

000

34

35

36

37

38

39

40

41

42

43

44

45

46

47

#ifndef INTARRAY_H

#define INTARRAY_H

#include

class IntArray

{

private:

} int m_length {

int * m_data {};

общедоступный:

IntArray (int length)

{

assert (length> 0);

m_data = новый int [длина] {};

m_length = длина;

}

// Мы не хотим разрешать создание копий IntArray.

IntArray (const IntArray &) = удалить;

IntArray & operator = (const IntArray &) = delete;

~ IntArray ()

{

удалить [] m_data;

}

void Erase ()

{

delete [] m_data;

// Нам нужно убедиться, что мы установили здесь m_data равным 0, иначе

// останется указывающим на освобожденную память!

m_data = nullptr;

m_length = 0;

}

int & operator [] (int index)

{

assert (index> = 0 && index

вернуть m_data [индекс];

}

int getLength () const {return m_length; }

};

#endif

Хотя этот класс предоставляет простой способ создания массивов целых чисел, что, если мы хотим создать массив двойных чисел? Используя традиционные методы программирования, нам пришлось бы создать совершенно новый класс! Вот пример DoubleArray, класса массива, используемого для хранения чисел типа double.

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

30

000

34

35

36

37

38

39

40

41

42

43

44

45

46

47

#ifndef DOUBLEARRAY_H

#define DOUBLEARRAY_H

#include

class DoubleArray

{

ngth:

{int} {int}

двойной * m_data {};

общедоступный:

DoubleArray (int length)

{

assert (length> 0);

m_data = новый двойной [длина] {};

m_length = длина;

}

DoubleArray (const DoubleArray &) = delete;

DoubleArray & operator = (const DoubleArray &) = delete;

~ DoubleArray ()

{

удалить [] m_data;

}

void Erase ()

{

delete [] m_data;

// Нам нужно убедиться, что мы установили здесь m_data равным 0, иначе

// останется указывающим на освобожденную память!

m_data = nullptr;

m_length = 0;

}

double & operator [] (int index)

{

assert (index> = 0 && index

вернуть m_data [индекс];

}

int getLength () const {return m_length; }

};

#endif

Несмотря на то, что кодовые листы очень длинные, вы заметите, что эти два класса почти идентичны! Фактически, единственное существенное отличие — это содержащийся тип данных (int vs double).Как вы, наверное, догадались, это еще одна область, где шаблоны можно найти с пользой, чтобы освободить нас от необходимости создавать классы, привязанные к одному конкретному типу данных.

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

Array.h:

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

30

000

34

35

36

37

38

39

40

41

42

43

44

45

46

49

0002 47

00030002 47

0003

51

52

53

54

55

56

#ifndef ARRAY_H

#define ARRAY_H

#include

шаблон

class Array

{

private:

private:

T * m_data {};

общедоступный:

Массив (длина int)

{

assert (длина> 0);

m_data = новый T [длина] {};

m_length = длина;

}

Массив (const Array &) = delete;

Массив & оператор = (const Массив &) = удалить;

~ Array ()

{

delete [] m_data;

}

void Erase ()

{

delete [] m_data;

// Нам нужно убедиться, что мы установили здесь m_data равным 0, иначе

// останется указывающим на освобожденную память!

m_data = nullptr;

m_length = 0;

}

T & operator [] (int index)

{

assert (index> = 0 && index

вернуть m_data [индекс];

}

// шаблонная функция getLength (), определенная ниже

int getLength () const;

};

// функции-члены, определенные вне класса, нуждаются в собственном объявлении шаблона

template

int Array :: getLength () const // обратите внимание, что имя класса — Array , а не Array

{

возврат m_length;

}

#endif

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

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

Вот краткий пример использования указанного выше класса шаблонного массива:

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

#include

#include «Массив.h «

int main ()

{

Array intArray (12);

Array doubleArray (12);

for (int count {0}; count

{

intArray [count] = count;

doubleArray [count] = count + 0.5;

}

для (int count {intArray.getLength () — 1}; count> = 0; —count)

std :: cout << intArray [count] << '\ t' << doubleArray [count] << '\ n';

return 0;

}

В этом примере печатается следующее:

11 11.5
10 10,5
9 9,5
8 8,5
7 7,5
6 6.5
5 5,5
4 4.5
3 3,5
2 2,5
1 1,5
0 0,5
 

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

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

Шаблонные классы в стандартной библиотеке

Теперь, когда мы рассмотрели классы шаблонов, вы должны понять, что теперь означает std :: vector — std :: vector на самом деле является классом шаблона, а int — параметром типа для шаблона! Стандартная библиотека полна предопределенных классов шаблонов, доступных для вашего использования.Мы рассмотрим это в следующих главах.

Разделение шаблонных классов

Шаблон — это не класс или функция — это шаблон, используемый для создания классов или функций. По сути, он работает не так, как обычные функции или классы. В большинстве случаев это не проблема. Однако есть одна область, которая часто вызывает проблемы у разработчиков.

Для классов, не являющихся шаблонами, общая процедура — поместить определение класса в файл заголовка, а определения функций-членов — в файл кода с аналогичным именем.Таким образом, исходный код класса компилируется как отдельный файл проекта. Однако с шаблонами это не работает. Рассмотрим следующее:

Array.h:

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

30

000

34

35

36

37

38

39

40

41

42

43

44

45

46

47

#ifndef ARRAY_H

#define ARRAY_H

#include

шаблон

class Array

{

private:

private:

T * m_data {};

общедоступный:

Массив (длина int)

{

assert (длина> 0);

m_data = новый T [длина] {};

m_length = длина;

}

Массив (const Array &) = delete;

Массив & оператор = (const Массив &) = удалить;

~ Array ()

{

delete [] m_data;

}

void Erase ()

{

delete [] m_data;

m_data = nullptr;

m_length = 0;

}

T & operator [] (int index)

{

assert (index> = 0 && index

вернуть m_data [индекс];

}

int getLength () const;

};

#endif

Массив.cpp:

#include «Array.h»

template

int Array :: getLength () const // обратите внимание, что имя класса — Array , а не Array

{

return m_length;

}

main.cpp:

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

#include «Массив.h «

int main ()

{

Array intArray (12);

Array doubleArray (12);

for (int count {0}; count

{

intArray [count] = count;

doubleArray [count] = count + 0.5;

}

для (int count {intArray.getLength () — 1}; count> = 0; —count)

std :: cout << intArray [count] << '\ t' << doubleArray [count] << '\ n';

return 0;

}

Приведенная выше программа компилируется, но вызывает ошибку компоновщика:

неразрешенный внешний символ "public: int __thiscall Array :: getLength (void)" (? GetLength @? $ Array @ H @@ QAEHXZ)
 

Чтобы компилятор мог использовать шаблон, он должен видеть как определение шаблона (а не только объявление), так и тип шаблона, используемый для создания экземпляра шаблона.Также помните, что C ++ компилирует файлы индивидуально. Когда заголовок Array.h # включен в main, определение класса шаблона копируется в main.cpp. Когда компилятор видит, что нам нужны два экземпляра шаблона, Array и Array , он создает их и компилирует как часть main.cpp. Однако когда он дойдет до компиляции Array.cpp по отдельности, он забудет, что нам нужны Array и Array , так что функция шаблона никогда не создается.Таким образом, мы получаем ошибку компоновщика, потому что компилятор не может найти определение для Array :: getLength () или Array :: getLength ().

Есть несколько способов обойти эту проблему.

Самый простой способ — просто поместить весь код вашего шаблона класса в файл заголовка (в этом случае поместите содержимое Array.cpp в Array.h под классом). Таким образом, когда вы #include заголовок, весь код шаблона будет в одном месте. Плюс этого решения в том, что оно простое.Обратной стороной здесь является то, что если класс шаблона используется во многих местах, вы получите множество локальных копий класса шаблона, что может увеличить время компиляции и компоновки (ваш компоновщик должен удалить повторяющиеся определения, поэтому он не должен раздуйте ваш исполняемый файл). Это наше предпочтительное решение, если только время компиляции или компоновки не станет проблемой.

Если вы чувствуете, что размещение кода Array.cpp в заголовке Array.h делает заголовок слишком длинным / беспорядочным, альтернативой является переименование массива.cpp в Array.inl (.inl означает встроенный), а затем включите Array.inl из нижней части заголовка Array.h. Это дает тот же результат, что и весь код в заголовке, но помогает сделать вещи немного чище.

Другие решения включают #include файлов .cpp, но мы не рекомендуем их из-за нестандартного использования #include.

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

templates.cpp:

// Убедитесь, что можно увидеть полное определение шаблона массива

#include «Array.h»

#include «Array.cpp» // здесь мы нарушаем передовой опыт, но только в одном месте

// # включить другие необходимые вам определения шаблонов .h и .cpp

template class Array ; // Явное создание экземпляра шаблона Array

template class Array ; // Явное создание экземпляра шаблона Array

// Здесь создаются экземпляры других шаблонов

Команда «шаблонный класс» заставляет компилятор явно создать экземпляр шаблонного класса.В приведенном выше случае компилятор выберет трафареты как Array , так и Array внутри templates.cpp. Поскольку templates.cpp находится внутри нашего проекта, он будет скомпилирован. Затем к этим функциям можно будет связать откуда угодно.

Этот метод более эффективен, но требует поддержки файла templates.cpp для каждой программы.


.

13.6 — Специализация шаблона класса

В предыдущем уроке 13.5 — Специализация шаблона функций мы увидели, как можно специализировать функции, чтобы обеспечить различную функциональность для определенных типов данных. Оказывается, можно не только специализировать функции, но и весь класс!

Рассмотрим случай, когда вы хотите создать класс, который хранит 8 объектов. Вот упрощенный класс для этого:

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

шаблон

class Storage8

{

private:

T m_array [8];

public:

void set (int index, const T & value)

{

m_array [index] = value;

}

const T & get (int index) const

{

return m_array [index];

}

};

Поскольку этот класс является шаблонным, он будет работать с любым заданным типом:

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

#include

int main ()

{

// Определить Storage8 для целых чисел

Storage8 intStorage;

для (int count {0}; count <8; ++ count)

intStorage.установить (количество, количество);

для (int count {0}; count <8; ++ count)

std :: cout << intStorage.get (count) << '\ n';

// Определите Storage8 для bool

Storage8 boolStorage;

для (int count {0}; count <8; ++ count)

boolStorage.set (count, count & 3);

std :: cout << std :: boolalpha;

для (int count {0}; count <8; ++ count)

{

std :: cout << boolStorage.получить (количество) << '\ п';

}

возврат 0;

}

В этом примере печатается:

0
1
2
3
4
5
6
7
ложный
правда
правда
правда
ложный
правда
правда
правда
 

Хотя этот класс полностью функциональный, оказывается, что реализация Storage8 гораздо более неэффективна, чем должна быть. Поскольку все переменные должны иметь адрес, а ЦП не может адресовать ничего меньше байта, все переменные должны иметь размер не менее байта.Следовательно, переменная типа bool использует весь байт, хотя технически ей нужен только один бит для хранения своего истинного или ложного значения! Таким образом, bool — это 1 бит полезной информации и 7 бит потраченного впустую места. Наш класс Storage8 , содержащий 8 булевых значений, содержит 1 байт полезной информации и 7 байт потраченного впустую пространства.

Оказывается, используя некоторую базовую логику битов, можно сжать все 8 логических значений в один байт, полностью исключив бесполезное пространство.Однако для этого нам потребуется обновить класс при использовании с типом bool, заменив массив из 8 bool переменной размером в один байт. Хотя мы могли бы создать для этого совершенно новый класс, у этого есть один серьезный недостаток: мы должны дать ему другое имя. Затем программист должен помнить, что Storage8 предназначен для типов, отличных от bool, тогда как Storage8Bool (или как там мы называем новый класс) предназначен для bools. Мы бы предпочли избежать этой ненужной сложности. К счастью, C ++ предоставляет нам лучший метод: специализацию шаблона класса.

Специализация шаблона класса

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

template <> // следующий шаблонный класс без шаблонных параметров

class Storage8 // мы специализируемся на Storage8 для bool

{

// Далее следует просто детали реализации стандартного класса

частный:

беззнаковый символ m_data {};

public:

void set (int index, bool value)

{

// Выясните, какой бит мы устанавливаем / снимаем

// Это поместит 1 в интересующий нас бит при включении / выключении

автоматическая маска {1 << index};

if (value) // Если мы устанавливаем бит

m_data | = mask; // Используйте побитовое или, чтобы включить этот бит

else // если мы немного отключим

m_data & = ~ mask; // побитовая и обратная маска для отключения этого бита

}

bool get (int index)

{

// Выясняем, какой бит мы получаем

автоматическая маска {1 << index};

// поразрядно — и чтобы получить значение интересующего нас бита

// Затем неявное приведение к логическому

return (m_data & mask);

}

};

Во-первых, обратите внимание, что мы начинаем с шаблона <> .Ключевое слово template сообщает компилятору, что все последующее является шаблоном, а пустые угловые скобки означают, что параметры шаблона отсутствуют. В этом случае нет никаких параметров шаблона, потому что мы заменяем единственный параметр шаблона (typename T) определенным типом (bool).

Затем мы добавляем к имени класса, чтобы обозначить, что мы специализируемся на bool-версии класса Storage8.

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

Обратите внимание, что в этом классе специализации используется один символ без знака (1 байт) вместо массива из 8 логических значений (8 байтов).

Теперь, когда мы объявляем класс типа Storage8 , где T не является логическим значением, мы получим версию, созданную по трафарету из общего шаблонного класса Storage8 .Когда мы объявляем класс типа Storage8 , мы получим только что созданную специализированную версию. Обратите внимание, что мы сохранили публично открытый интерфейс обоих классов одинаковым — в то время как C ++ дает нам свободу добавлять, удалять или изменять функции Storage8 по своему усмотрению, сохранение согласованного интерфейса означает, что программист может использовать либо класс точно так же.

Мы можем использовать тот же пример, что и раньше, чтобы показать экземпляры Storage8 и Storage8 :

1

2

3

4

5

6

7

8

9

10

11

12

13

140002

14

18

19

20

21

22

23

24

25

26

27

28

29

31

int main ()

{

// Определите Storage8 для целых чисел (создает экземпляр Storage8 , где T = int)

Storage8 intStorage;

для (int count {0}; count <8; ++ count)

{

intStorage.установить (количество, количество);

}

для (int count {0}; count <8; ++ count)

{

std :: cout << intStorage.get (count) << '\ n';

}

// Определить Storage8 для bool (создает экземпляр специализации Storage8 )

Storage8 boolStorage;

для (int count {0}; count <8; ++ count)

{

boolStorage.установить (счетчик, счет & 3);

}

std :: cout << std :: boolalpha;

для (int count {0}; count <8; ++ count)

{

std :: cout << boolStorage.get (count) << '\ n';

}

возврат 0;

}

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

0
1
2
3
4
5
6
7
ложный
правда
правда
правда
ложный
правда
правда
правда
 

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


.

c ++ — Специализация конструктора шаблона класса шаблона

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
  3. Вакансии Программирование и связанные с ним технические возможности карьерного роста
  4. Талант Нанимайте технических специалистов и создавайте свой бренд работодателя
  5. Реклама Обратитесь к разработчикам и технологам со всего мира
  6. О компании
.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *