c ++中“泛型编程”的含义是什么?

时间:2010-10-05 09:26:57

标签: c++

c ++中泛型编程的含义是什么?

另外,我试图找出容器,迭代器,以及它们的不同类型。

6 个答案:

答案 0 :(得分:56)

通用编程意味着您不是编写按原样编译的源代码,而是编写源代码的“模板”,编译器在编译过程中将其转换为源代码。通用编程的最简单示例是容器类,例如包含其他对象集合的数组,列表或映射。但通用编程还有很多。在C ++(并称为元编程)的上下文中,它意味着编写在编译时评估的程序。

泛型编程的基本示例是容器模板:在像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;
}

模板泛型,因为编译器会将模板转换为实际代码。请注意,如果您没有实例化模板,则不会为其生成任何的代码。另一方面,如果您声明MyContainer<int>MyContainer<float>MyContainer<String>,编译器将创建代码的三个版本,每个版本都有一个不同的类型。将涉及一些优化,但基本上您的模板代码将实例化为三种新类型。

迭代器是一种设计模式,在Gamma等人的开创性着作“设计模式”中得到了普及。这是迭代容器类内容的模式。与使用for循环不同,迭代器是指向容器成员的类的实例,并为您提供统一的接口来遍历容器以及访问成员。看一下这个例子:

// 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++;
}

在这个C ++示例中,我正在使用类型int即时消息模板 QList。 QList存储一个容器类,用于存储对象列表。在这个例子中,我们将使用它来存储整数。

然后我创建一个迭代器 i来遍历列表。 myList.begin()返回指向列表第一个元素的迭代器。我们可以将迭代器与另一个迭代器myList.end()进行比较,该迭代器在列表的最后一个元素之后指向。如果两个迭代器都相同,我们知道我们已经通过了最后一个元素。在循环中,我们通过使用*i访问元素来打印元素,然后使用i++转到下一个元素。

请注意,在此示例中,*++是重载运算符,并由迭代器类重新实现。在没有运算符重载的编程语言中,可能有像i.element()i.next()这样的方法执行相同的任务。重要的是要看到i不是一个指针,而是一个只是模仿指针行为的整个类。

迭代器有什么好处?它们提供了一种访问容器类成员的统一方法,完全不考虑容器类在内部的实现方式。无论你想遍历列表,映射还是树,迭代器类(应该)总是以相同的方式工作。

答案 1 :(得分:13)

容器

在C ++中,容器是一个允许您存储对象的类。例如,标准库std::vector<T>是一个可调整大小的数组,它存储某种类型T的对象。为了正式被视为容器类,它必须公开某些功能以便于通用编程。我可以引用C ++标准的确切要求,但对于大多数用途,重要的容器类是标准库中的容器类:vectordequelist,{{1 },mapset / multimap

其中一个重要要求是它们必须允许迭代器访问。

迭代

“迭代器”在这里意味着两件事:它是设计模式的名称,但在C ++中,它也是该设计模式的特定表达式的名称。 C ++迭代器是一种允许使用类似指针的语法遍历一系列元素的类型。

例如,如果你有一个数组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)

或者如果我们编写一个对int求平方的函数,例如:

std::sort(first, last);

然后我们可以将它应用于整个序列:

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实现与链表和数组一起使用,甚至与您自己的自制容器类一起使用。

通用编程

通用编程基本上是您的代码应尽可能通用的想法。如上面的迭代器示例所示,我们提出了一个通用的函数集,类型必须支持这些函数才能被称为迭代器,然后我们编写与任何迭代器类型一起使用的算法。 / p>

将此与传统的面向对象编程进行比较,其中迭代器必须通过继承某种sort接口来“证明”它们是迭代器。这会阻止我们使用原始指针作为迭代器,因此我们会失去通用性。

在C ++中,通用编程,我们不需要官方接口。我们只是使用模板编写算法,因此它们接受任何类型,它恰好看起来像一个迭代器,无论它们在何处,何时以及如何定义,以及它们是否来自公共基类或接口。

答案 2 :(得分:7)

在最简单的定义中,泛型编程是一种计算机编程风格,其中算法是根据待指定的后期类型编写的,然后在需要时将实例化为作为参数提供的特定类型。

答案 3 :(得分:1)

作为一个历史兴趣点,模板之前的C ++版本是语言的一部分,其中包含“generic.h”,其中包含可以扩展为类声明的预处理器宏。因此,对于类,您可以拥有一个通用模式(“模板”),当您将它们扩展为实际的类声明时,可以通过将某些参数传递给宏来改变它们。 但是,预处理器宏不是类型安全的并且处理起来有点笨拙,并且由于这些原因,它们在C ++代码中的使用显着下降; C ++采用了更多功能的模板作为语言的元素,但术语“通用”编程仍然存在。 “泛型”现在在其他编程语言中用作美化类型转换。 除此之外,这个问题已经得到了专业的回答。

答案 4 :(得分:0)

泛型编程:几乎只涉及模板。

container:一个struct或class,它包含自己的数据和作用于该数据的方法。

Iterator:它是一个指向你可以迭代的内存地址的指针(就像一个数组)。

如果上述任何一个错误,请纠正我。

答案 5 :(得分:0)

类型参数的概念,它可以设计推迟一个或多个类型的规范的类和方法,直到通过客户端代码声明和实例化类或方法。