C++/迭代器如何为一组 class 对象工作?
C++ / How does a iterator work for a Set of class object?
我一直在自学 C++,发现了一件有趣的事情。
The most obvious form of iterator is a pointer.
所以,我曾经认为迭代器对象的工作方式几乎与指针相同(例如int *i
);
不过,现在我想说迭代器对象更像是指针的指针(例如int **i
)而不是指针(int *i
)会更准确。
我在编写以下代码时注意到了这一点。
set<Point*, Point> points; //This class encapsulates x and y coordinates for a 2 dimensional point
set<Point*, Point>::iterator it;
int x = 22;
int y = 4;
Point* pt = new Point(x, y);
points.insert(pt);
//Similar statements are here, to insert other Point objects with different arguments
for (it = points.begin(); it != points.end(); it++) {
cout << "**it: " << **it << ", *it :" << *it << ", Address : " << &it << endl;
}
因此,
**it
显示指针 class 对象的值
*it
显示地址
&it
显示了 it
对象的地址
所以,迭代器对象(it
)和**it
基本一样,这样说对吗?
另一个与迭代器有点不同的问题:
如果我需要制作一组 class 对象,例如:set<ClassName*, ClassName> SetName;
,正确的方法是什么? (只要此 class 包含可比较的数据类型,如 int
或 double
)
如果您能提供一些建议,我将不胜感激。
这是一个错误的假设。在您的示例中,集合的 value_type
是指针 Point *
。 *it
为您提供集合中的一个元素,该元素是对该 value_type
的某个对象的引用,该对象的类型为 Point *
和 ++it
"points" 到下一个集合中的元素。所以迭代器的行为方式与指向 value_type
.
的对象的指针相同
当您使用像 **it
这样的表达式时,第二个取消引用不会应用于迭代器。它应用于集合中的对象。你可以用下面的方式想象表达式 **it
Point *pp = *it;
Point p = *pp;
容器的迭代器负责为您提供对容器元素的访问。因此,如果容器中的元素具有 value_type
类型,则迭代器提供对此 value_type 的这些元素的访问。元素又可以是指向对象的指针,甚至可以是指向对象的指针等等。
至于你的第二个问题,那么如果 class 有相应的运算符函数并且 class 本身有一些简单的默认构造函数那么你可以使用这种方法,尽管最好定义一个单独的比较器或简单地为 class 的对象定义 operator <
。在最后一种情况下你可以写
std::set<Point> s;
没有明确的第二个模板参数。
这是您的方法的演示程序
#include <iostream>
#include <set>
int main()
{
struct Point
{
int x, y;
bool operator ()( const Point &p1, const Point &p2 ) const
{
return p1.x < p2.x && p1.y < p2.y;
}
};
std::set<Point, Point> s;
s.insert( { 2, 2 } );
s.insert( { 1, 1 } );
for ( const Point &p : s ) std::cout << p.x << ' ' << p.y << std::endl;
return 0;
}
程序输出为
1 1
2 2
我一直在自学 C++,发现了一件有趣的事情。
The most obvious form of iterator is a pointer.
所以,我曾经认为迭代器对象的工作方式几乎与指针相同(例如int *i
);
不过,现在我想说迭代器对象更像是指针的指针(例如int **i
)而不是指针(int *i
)会更准确。
我在编写以下代码时注意到了这一点。
set<Point*, Point> points; //This class encapsulates x and y coordinates for a 2 dimensional point
set<Point*, Point>::iterator it;
int x = 22;
int y = 4;
Point* pt = new Point(x, y);
points.insert(pt);
//Similar statements are here, to insert other Point objects with different arguments
for (it = points.begin(); it != points.end(); it++) {
cout << "**it: " << **it << ", *it :" << *it << ", Address : " << &it << endl;
}
因此,
**it
显示指针 class 对象的值*it
显示地址&it
显示了it
对象的地址
所以,迭代器对象(it
)和**it
基本一样,这样说对吗?
另一个与迭代器有点不同的问题:
如果我需要制作一组 class 对象,例如:set<ClassName*, ClassName> SetName;
,正确的方法是什么? (只要此 class 包含可比较的数据类型,如 int
或 double
)
如果您能提供一些建议,我将不胜感激。
这是一个错误的假设。在您的示例中,集合的 value_type
是指针 Point *
。 *it
为您提供集合中的一个元素,该元素是对该 value_type
的某个对象的引用,该对象的类型为 Point *
和 ++it
"points" 到下一个集合中的元素。所以迭代器的行为方式与指向 value_type
.
当您使用像 **it
这样的表达式时,第二个取消引用不会应用于迭代器。它应用于集合中的对象。你可以用下面的方式想象表达式 **it
Point *pp = *it;
Point p = *pp;
容器的迭代器负责为您提供对容器元素的访问。因此,如果容器中的元素具有 value_type
类型,则迭代器提供对此 value_type 的这些元素的访问。元素又可以是指向对象的指针,甚至可以是指向对象的指针等等。
至于你的第二个问题,那么如果 class 有相应的运算符函数并且 class 本身有一些简单的默认构造函数那么你可以使用这种方法,尽管最好定义一个单独的比较器或简单地为 class 的对象定义 operator <
。在最后一种情况下你可以写
std::set<Point> s;
没有明确的第二个模板参数。
这是您的方法的演示程序
#include <iostream>
#include <set>
int main()
{
struct Point
{
int x, y;
bool operator ()( const Point &p1, const Point &p2 ) const
{
return p1.x < p2.x && p1.y < p2.y;
}
};
std::set<Point, Point> s;
s.insert( { 2, 2 } );
s.insert( { 1, 1 } );
for ( const Point &p : s ) std::cout << p.x << ' ' << p.y << std::endl;
return 0;
}
程序输出为
1 1
2 2