c ++中“通用编程”的含义是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3862378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the meaning of "generic programming" in c++?
提问by bunty
What is the meaning of generic programmingin c++?
c ++中泛型编程的含义是什么?
Also, I am trying to figure out what container, iterator, and different types of them mean.
另外,我试图弄清楚container 、 iterator以及它们的不同类型是什么意思。
回答by WolfgangP
Generic programmingmeans that you are not writing source code that is compiled as-is but that you write "templates" of source codes that the compiler in the process of compilation transforms into source codes. The simplest example for generic programming are container classeslike arrays, lists or maps that contain a collection of other objects. But there's much more to generic programming. In the context of C++ (and called meta programming) it means to write programs that are evaluated at compile time.
通用编程意味着您不是编写按原样编译的源代码,而是编写源代码的“模板”,编译器在编译过程中将其转换为源代码。泛型编程的最简单示例是包含其他对象集合的容器类,如数组、列表或映射。但是泛型编程还有很多。在 C++ 的上下文中(称为元编程),它意味着编写在编译时求值的程序。
A basic example of generic programming are templates of containers: In a statically typed language like C++ you would have to declare separate containers that hold integers, floats, and other types or deal with pointers to void
and therefore losing all type information. Templates which are the C++ way of generic programming leverage this constraint by letting you define classes where one or more parameters are unspecified at the time you define the class. When you instance the template later you tell the compiler which type it should use to create the class out of the template. Example:
泛型编程的一个基本示例是容器模板:在像 C++ 这样的静态类型语言中,您必须声明单独的容器来保存整数、浮点数和其他类型,或者处理指向void
并因此丢失所有类型信息的指针。作为通用编程的 C++ 方式的模板通过让您定义类来利用这一约束,其中一个或多个参数在您定义类时未指定。当您稍后实例化模板时,您告诉编译器它应该使用哪种类型从模板中创建类。例子:
template<typename T>
class MyContainer
{
// Container that deals with an arbitrary type T
};
void main()
{
// Make MyContainer take just ints.
MyContainer<int> intContainer;
}
Templates are genericbecause the compiler translates the template into actual code. Note that in the case you don't instantiate your template no code will be generated for it at all. On the other hand, if you declare a MyContainer<int>
, a MyContainer<float>
, and a MyContainer<String>
the compiler will create threeversions of your code each of them having a different type. There will be some optimizations involved but basically your template code will be instantianted to three new types.
模板是通用的,因为编译器将模板转换为实际代码。注意,在情况下,你不要实例模板没有代码会为它生成在所有。另一方面,如果您声明 a MyContainer<int>
、 aMyContainer<float>
和 a MyContainer<String>
,编译器将创建您的代码的三个版本,每个版本都具有不同的类型。将涉及一些优化,但基本上您的模板代码将实例化为三种新类型。
Iteratorsare a design patternthat were popularized in the seminal book "Design Patterns" by Gamma et al. It's a pattern to iterate over the content of a container class. Unlike using a for
-loop an iterator is an instance of a class that points to a member of the container and gives you an unified interface to traverse the container as well as accessing the members. Take look at this example:
迭代器是一种设计模式,在 Gamma 等人的开创性著作“设计模式”中得到了普及。这是一种迭代容器类内容的模式。与使用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++;
}
In this C++ example I'm instantating a templateQList with type int
. QList a containerclass that stores a list of objects. In this example we will use it to store integers.
在这个 C++ 示例中,我正在实例化一个类型为QList的模板int
。QList 一个容器类,用于存储对象列表。在这个例子中,我们将使用它来存储整数。
Then I create an iteratori
to traverse through the list. myList.begin()
returns an iterator that points to the first element of the list. We can compare the iterator with another iterator myList.end()
that points afterthe last element of the list. If both iterators are the same we know that we have passed the last elment. In the loop we're printing the element by accessing it with *i
and go to the next element with i++
.
然后我创建一个迭代器i
来遍历列表。myList.begin()
返回一个指向列表第一个元素的迭代器。我们可以将迭代器与另一个myList.end()
指向列表最后一个元素之后的迭代器进行比较。如果两个迭代器相同,我们就知道我们已经通过了最后一个元素。在循环中,我们通过访问它来打印元素*i
并使用 转到下一个元素i++
。
Note that in this example *
and ++
are overloaded operators and reimplemented by the iterator class. In a programming language without operator overloading there could be methods like i.element()
or i.next()
that do the same task. It's important to see that i
is not a pointer but a whole class that just mimics the behaviour of a pointer.
请注意,在此示例中,*
和++
是重载运算符并由迭代器类重新实现。在没有运算符重载的编程语言中,可能有类似i.element()
或i.next()
执行相同任务的方法。重要的是要看到它i
不是一个指针,而是一个只是模仿指针行为的整个类。
What's the benefit of iterators? They provide a unified way to access the members of a container class, completely indepented on how the container class is implemented internally. No matter if your want to traverse a list, map or tree, the iterator classes (should) always work the same way.
迭代器有什么好处?它们提供了一种访问容器类成员的统一方式,完全独立于容器类的内部实现方式。无论您是要遍历列表、地图还是树,迭代器类(应该)始终以相同的方式工作。
回答by jalf
Container
容器
In C++, a container is a class that allows you to store objects. For example the standard library std::vector<T>
is a resizable array which stores objects of some type T. In order to be formally considered a container class, it must expose certain functionality in order to facilitate generic programming. I could quote the exact requirements from the C++ standard, but for most purposes, the container classes that matter are the ones from the standard library: vector
, deque
, list
, map
, set
and multimap
/multiset
.
在 C++ 中,容器是一个允许您存储对象的类。例如,标准库std::vector<T>
是一个可调整大小的数组,它存储某种类型 T 的对象。为了正式被视为容器类,它必须公开某些功能以促进泛型编程。我可以引述来自C ++标准的具体要求,但对于大多数的目的,容器类此事与标准库中的:vector
,deque
,list
,map
,set
和multimap
/ multiset
。
One of the important requirements is that they must allow iteratoraccess.
重要的要求之一是它们必须允许迭代器访问。
Iterator
迭代器
"Iterator" can mean two things here: It is the name of a design pattern, but in C++ it is also the name of a specific expression of that design pattern. A C++ iterator is a type that allows traversal over a sequence of elements using a pointer-like syntax.
“迭代器”在这里可以表示两件事:它是设计模式的名称,但在 C++ 中,它也是该设计模式的特定表达式的名称。C++ 迭代器是一种允许使用类似指针的语法遍历元素序列的类型。
For example, if you have an array int a[10]
, you can use a plain pointer as an iterator:
例如,如果您有一个数组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
If I had a linked list, such as std::list<int> l
, I could do much the same, although now my iterators are no longer just pointers, but instead a class type implemented to work specifically with std::list
:
如果我有一个链表,例如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
or with a vector std::vector<int> v
:
或使用向量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
The important thing about iterators is that they give us a uniform syntax for traversing sequences of elements, regardless of how the sequence is stored in memory(or even ifit is stored in memory. An iterator could be written to iterate over the contents of a database on disk. Or we can use iterator wrappers to make a stream such as std::cin
look like a sequence of objects too:
关于迭代器最重要的是,他们给我们一个统一的语法遍历元素序列,无论顺序如何存储在内存中(或者甚至如果它被存储在内存中。迭代器可以在内容被写入迭代磁盘上的数据库。或者我们可以使用迭代器包装器使流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
although because this wraps a regular stream, it is a more limited type of iterator (you can't move backwards, for example, which means not all of the following algorithms work with stream iterators.
尽管因为这包装了一个常规流,所以它是一种更有限的迭代器(例如,您不能向后移动,这意味着并非所有以下算法都适用于流迭代器。
Now, given any of these iterator types, we can use all the standard library algorithms which are designed to work with iterators. For example, to find the first element in the sequence with value 4
:
现在,给定这些迭代器类型中的任何一种,我们可以使用所有旨在与迭代器一起使用的标准库算法。例如,要查找序列中具有 value 的第一个元素4
:
std::find(first, last, 4); // return the first iterator which equals 4 and which is located in the interval [first, last)
Or we can sort the sequence (doesn't work with stream iterators):
或者我们可以对序列进行排序(不适用于流迭代器):
std::sort(first, last);
or if we write a function which squares an int, such as this:
或者,如果我们编写一个对 int 求平方的函数,例如:
int square(int i) { return i * i; }
then we can apply it to the entire sequence:
然后我们可以将其应用于整个序列:
// 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);
That's the advantage of iterators: they abstract away the details of the container, so that we can apply generic operations on anysequence. Thanks to iterators, the same find
or sort
implementation works with linked lists as well as arrays, or even with your own home-made container classes.
这就是迭代器的优点:它们抽象出容器的细节,以便我们可以对任何序列应用通用操作。多亏了迭代器,相同的find
或sort
实现可以与链表和数组一起使用,甚至可以与您自己的自制容器类一起使用。
Generic Programming
通用编程
Generic programming is basically the idea that your code should be as generic as possible. As shown in the iterator examples above, we come up with a common set of functionality that a type must support in order to be called an iterator, and then we write algorithms that work with anyiterator type.
泛型编程基本上是你的代码应该尽可能泛型的想法。如上面的迭代器示例所示,我们提出了一个类型必须支持的一组通用功能才能被称为迭代器,然后我们编写了适用于任何迭代器类型的算法。
Compare this with traditional object-oriented programming, where iterators would have to "prove" that they're iterators by inheriting from some kind of IIterator
interface. That would prevent us from using raw pointers as iterators, so we'd lose genericity.
将此与传统的面向对象编程进行比较,在传统的面向对象编程中,迭代器必须通过从某种IIterator
接口继承来“证明”它们是迭代器。这将阻止我们使用原始指针作为迭代器,因此我们将失去通用性。
In C++, with generic programming, we don't need the official interface. We just write the algorithms using templates, so they accept anytype which just so happens to look likean iterator, regardless of where, when and how they're defined, and whether or not they derive from a common base class or interface.
在 C++ 中,使用泛型编程,我们不需要官方接口。我们只是使用模板编写算法,因此它们接受任何恰好看起来像迭代器的类型,无论它们在何处、何时以及如何定义,也不管它们是否从公共基类或接口派生而来。
回答by cseav
In the simplest definition, generic programming is a style of computer programming in which algorithms are written in terms of to-be-specified-later types that are then instantiated when needed for specific types provided as parameters.
在最简单的定义中,泛型编程是一种计算机编程风格,其中算法是根据稍后指定的类型编写的,然后在需要时为作为参数提供的特定类型进行实例化。
回答by Alexander Rautenberg
As a point of historical interest, the versions of C++ that came before templates were part of the language had a "generic.h" that contained preprocessor macros which could be expanded to class declarations. So you could have a generic schema ("template") for a class which you could vary by passing certain parameters into the macros when you expanded them to actual class declarations. However, preprocessor macros are not type safe and a bit clumsy to handle, and their use in C++ code significantly declined due to these reasons; C++ adopted the more versatile templates as elements of the language, but the term "generic" programming lived on. "Generics" are now used in other programming languages as glorified type casts. Other than that, the question has already been expertly answered.
作为历史兴趣点,在模板是语言的一部分之前出现的 C++ 版本有一个“ generic.h”,其中包含可以扩展为类声明的预处理器宏。所以你可以有一个类的通用模式(“模板”),当你将它们扩展到实际的类声明时,你可以通过将某些参数传递给宏来改变它们。然而,预处理器宏不是类型安全的,处理起来有点笨拙,由于这些原因,它们在 C++ 代码中的使用显着下降;C++ 采用了更通用的模板作为语言的元素,但术语“通用”编程仍然存在。“泛型”现在在其他编程语言中用作美化的类型转换。除此之外,
回答by Alexander Rafferty
generic programming: pretty much just involves templates.
通用编程:几乎只涉及模板。
container: A struct or class, which contains its own data and methods that act on that data.
容器:一个结构或类,它包含自己的数据和作用于该数据的方法。
Iterator: It is a pointer to some memory address that you can iterate through (like an array).
迭代器:它是指向可以迭代的某个内存地址的指针(如数组)。
Correct me if wrong on any of the above.
如果以上任何一条错误,请纠正我。
回答by Robert Rocha
the concept of type parameters, which make it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated by client code.
类型参数的概念,这使得设计类和方法成为可能,这些类和方法将一种或多种类型的规范推迟到客户端代码声明和实例化类或方法之前。