В чем смысл общего программирования в С++?
Кроме того, я пытаюсь выяснить, что означает контейнер, iterator и разные типы.
В чем смысл общего программирования в С++?
Кроме того, я пытаюсь выяснить, что означает контейнер, iterator и разные типы.
Общее программирование означает, что вы не пишете исходный код, который компилируется как есть, но вы пишете "шаблоны" исходных кодов, которые компилятор в процессе компиляции преобразуется в исходные коды. Простейшим примером для общего программирования являются классы контейнеров, такие как массивы, списки или карты, содержащие коллекцию других объектов. Но есть еще много общего для программирования. В контексте С++ (и называется мета-программирование) это означает, что программы, которые оцениваются во время компиляции, записываются.
Основным примером универсального программирования являются шаблоны контейнеров: на статически типизированном языке, таком как С++, вам придется объявлять отдельные контейнеры, содержащие целые числа, поплавки и другие типы, или иметь дело с указателями на void
и, следовательно, потерять все типы Информация. Шаблоны, которые являются способом общего программирования на С++, используют это ограничение, позволяя вам определять классы, когда один или несколько параметров не определены в момент определения класса. Когда вы экземпляр шаблона позже, вы сообщите компилятору, который он должен использовать, чтобы создать класс из шаблона. Пример:
template<typename T>
class MyContainer
{
// Container that deals with an arbitrary type T
};
void main()
{
// Make MyContainer take just ints.
MyContainer<int> intContainer;
}
Шаблоны generic, потому что компилятор переводит шаблон в фактический код. Обратите внимание, что в случае, если вы не создаете экземпляр своего шаблона, для него не будет создан код. С другой стороны, если вы объявите MyContainer<int>
, a MyContainer<float>
и a MyContainer<String>
, то компилятор будет создавать три версии вашего кода, каждый из которых имеет другой тип. Будут задействованы некоторые оптимизации, но в основном ваш шаблон кода будет обновлен тремя новыми типами.
Итераторы - это шаблон дизайна, который был популяризирован в оригинальной книге "Шаблоны проектирования" Gamma et al. Это шаблон для перебора содержимого класса контейнера. В отличие от использования for
-loop, итератор представляет собой экземпляр класса, который указывает на член контейнера и дает вам единый интерфейс для перемещения контейнера, а также доступа к членам. Взгляните на этот пример:
// Instanciate template QList with type int
QList<int> myList;
// put some ints into myList
// Copyconstruct iterator that points to the
// first member of the list.
QList<int>::iterator i = myList.begin();
// Iterate through the list
while (i != myList.end()) {
std::cout << *i << std::endl;
i++;
}
В этом примере на С++ я создаю шаблон QList с типом int
. QList контейнер класс, который хранит список объектов. В этом примере мы будем использовать его для хранения целых чисел.
Затем я создаю iterator i
для прохождения по списку. myList.begin()
возвращает итератор, который указывает на первый элемент списка. Мы можем сравнить итератор с другим итератором myList.end()
, который указывает после последнего элемента списка. Если оба итератора одинаковы, мы знаем, что мы прошли последний экзамен. В цикле мы печатаем элемент, обращаясь к нему с помощью *i
и переходим к следующему элементу с помощью i++
.
Обратите внимание, что в этом примере *
и ++
являются перегруженными операторами и переопределены классом итератора. На языке программирования без перегрузки оператора могут быть такие методы, как i.element()
или i.next()
, которые выполняют одну и ту же задачу. Важно заметить, что i
не является указателем, а целым классом, который просто имитирует поведение указателя.
Какая польза от итераторов? Они обеспечивают единый способ доступа к членам класса контейнера, полностью зависящим от того, как класс контейнера реализован внутри. Независимо от того, хотите ли вы перемещаться по списку, карте или дереву, классы итератора (должны) всегда работают одинаково.
В С++ контейнер - это класс, который позволяет хранить объекты. Например, стандартная библиотека std::vector<T>
представляет собой изменяемый размер массива, который хранит объекты некоторого типа T. Чтобы формально считаться классом контейнера, он должен выставлять определенные функции для облегчения общего программирования. Я мог бы привести конкретные требования к стандарту С++, но для большинства целей соответствующие классы контейнеров являются таковыми из стандартной библиотеки: vector
, deque
, list
, map
, set
и multimap
/multiset
.
Одним из важных требований является то, что они должны разрешать доступ к итератору.
"Итератор" может означать две вещи здесь: это имя шаблона проектирования, но в С++ это также имя конкретного выражения этого шаблона проектирования. Итератор С++ - это тип, который позволяет обходить последовательность элементов, используя синтаксис, подобный указателю.
Например, если у вас есть массив int a[10]
, вы можете использовать простой указатель как итератор:
int* first = a; // create an iterator that points to the beginning of the array
++first; // make the iterator point to the second element
int i = *first; // get the value of the element pointed to by the iterator
int* last = a+10; //create an "end" iterator, one which points one past the end of the array
Если бы у меня был связанный список, например std::list<int> l
, я мог бы сделать то же самое, хотя теперь мои итераторы уже не просто указатели, а вместо этого тип класса, реализованный специально для работы с std::list
:
std::list<int>::iterator first = l.begin(); // create an iterator that points to the beginning of the list
++first; // make the iterator point to the second element
int i = *first; // get the value of the element pointed to by the iterator
std::list<int>::iterator last = l.end(); //create an "end" iterator, one which points one past the end of the list
или с вектором std::vector<int> v
:
std::vector<int>::iterator first = v.begin(); // create an iterator that points to the beginning of the vector
++first; // make the iterator point to the second element
int i = *first; // get the value of the element pointed to by the iterator
std::list<int>::iterator last = v.end(); //create an "end" iterator, one which points one past the end of the vector
Важная информация об итераторах заключается в том, что они дают нам единый синтаксис для прохождения последовательностей элементов, независимо от того, как последовательность хранится в памяти (или даже если она хранится в памяти. Итератор может быть записан для итерации по содержимое базы данных на диске. Или мы можем использовать обертки итератора, чтобы поток, такой как std::cin
, также выглядел как последовательность объектов:
std::istream_iterator<int>(std::cin) first;
++first; // make the iterator point to the second element
int i = *first; // get the value of the element pointed to by the iterator
std::list<int>::iterator last; //create an "end" iterator, which marks the end of the stream
хотя из-за того, что это обертывает регулярный поток, это более ограниченный тип итератора (вы не можете двигаться назад, например, что означает, что не все из следующих алгоритмов работают с итераторами потоков.
Теперь, учитывая любой из этих типов итераторов, мы можем использовать все стандартные библиотечные алгоритмы, которые предназначены для работы с итераторами. Например, чтобы найти первый элемент в последовательности со значением 4
:
std::find(first, last, 4); // return the first iterator which equals 4 and which is located in the interval [first, last)
Или мы можем сортировать последовательность (не работает с итераторами потоков):
std::sort(first, last);
или если мы напишем функцию, которая квадратизирует int, например:
int square(int i) { return i * i; }
то мы можем применить его ко всей последовательности:
// for every element in the range [first, last), apply the square function, and output the result into the sequence starting with first
std::transform(first, last, first, square);
Это преимущество итераторов: они абстрагируют детали контейнера, поэтому мы можем применять общие операции для любой последовательности. Благодаря итераторам такая же реализация find
или sort
работает со связанными списками, а также с массивами или даже с вашими собственными классами контейнеров для дома.
Общее программирование - это в основном идея о том, что ваш код должен быть как можно более общим. Как показано в приведенных выше примерах итератора, мы предлагаем общий набор функций, которые тип должен поддерживать для того, чтобы быть названным итератором, а затем мы пишем алгоритмы, которые работают с любым типом итератора.
Сравните это с традиционным объектно-ориентированным программированием, где итераторы должны "доказать", что они являются итераторами, наследуя от какого-то интерфейса IIterator
. Это помешало бы нам использовать исходные указатели в качестве итераторов, поэтому мы потеряли бы природу.
В С++ с общим программированием нам не нужен официальный интерфейс. Мы просто пишем алгоритмы с использованием шаблонов, поэтому они принимают любой тип, который так выглядит, как итератор, независимо от того, где, когда и как они определены, и независимо от того, происходят они из общего базового класса или интерфейса.
В простейшем определении, общее программирование - это стиль компьютерного программирования, в котором алгоритмы записываются в терминах типов, подлежащих заданию-позже, которые затем создаются при необходимости для определенных типов, предоставляемых в качестве параметров.
В качестве точки, представляющей исторический интерес, версии С++, которые приходили перед шаблонами, были частью языка, имеющего " generic.h", который содержащиеся макросы препроцессора, которые могут быть расширены для объявлений классов. Таким образом, у вас может быть общая схема ( "шаблон" ) для класса, который вы можете изменить, передав определенные параметры в макросы, когда вы расширили их до фактических деклараций классов. Однако макросы препроцессора не являются безопасными по типу и немного неуклюжими для обработки, и их использование в коде на С++ значительно уменьшилось из-за этих причин; С++ принял более универсальные шаблоны в качестве элементов языка, но термин "общее" программирование продолжался. "Дженерики" теперь используются на других языках программирования в качестве прославленных типов. Помимо этого, этот вопрос уже получил квалифицированный ответ.
общее программирование: в значительной степени просто используются шаблоны.
container: структура или класс, который содержит свои собственные данные и методы, которые действуют на эти данные.
Итератор: это указатель на некоторый адрес памяти, через который вы можете перебирать (например, массив).
Исправьте меня, если не ошибаетесь ни на одном из вышеперечисленных.
понятие параметров типа, которые позволяют создавать классы и методы, которые откладывают спецификацию одного или нескольких типов до тех пор, пока класс или метод не будут объявлены и не будут созданы кодом клиента.