C++ 如何在C++;使用自定义类
我是C/C++编程新手,但我已经用C#编程1.5年了。我喜欢C++,我喜欢列表类,所以我想把C++中的列表类作为一个练习来做。C++ 如何在C++;使用自定义类,c++,list,c++11,foreach,C++,List,C++11,Foreach,我是C/C++编程新手,但我已经用C#编程1.5年了。我喜欢C++,我喜欢列表类,所以我想把C++中的列表类作为一个练习来做。 List<int> ls; int whatever = 123; ls.Add(1); ls.Add(235445); ls.Add(whatever); 这显然不适用于我的列表实现。我想我可以做一些宏魔术,但这感觉像一个巨大的黑客。事实上,最让我困扰的是通过这样的类型: #define foreach(type, var, list)\ int _i_
List<int> ls;
int whatever = 123;
ls.Add(1);
ls.Add(235445);
ls.Add(whatever);
这显然不适用于我的列表实现。我想我可以做一些宏魔术,但这感觉像一个巨大的黑客。事实上,最让我困扰的是通过这样的类型:
#define foreach(type, var, list)\
int _i_ = 0;\
##type var;\
for (_i_ = 0, var=list[_i_]; _i_<list.Length();_i_++,var=list[_i_])
foreach(int,i,ls){
doWork(i);
}
#定义foreach(类型、变量、列表)\
int(i)=0 ;\
##类型var\
对于(i i= 0,var =列表[Aii];S.Ii语法智能提示不是C++,或者是一些MSVC扩展。
C++11具有遍历容器元素的功能。您需要实现
begin()
和end()
类的成员函数,该函数将分别将迭代器返回到第一个元素和最后一个元素。当然,这意味着您也需要实现适合您的类的迭代器。如果您真的想走这条路,您可能想看看;它减少了您自己实现迭代器的许多痛苦
之后,您将能够编写以下内容:
for( auto const& l : ls ) {
// do something with l
}
另外,由于您是C++的新手,所以我想知道标准库有好几类。
< P>首先,<代码> C++ >代码>中的<<代码>循环的<代码>与C><代码>不同(也称为<<代码>范围为循环< /COD>),其形式为:
for(<type> <name> : <collection>) { ... }
在封面下,这有效地使用了begin()
和end()
成员函数,它们返回迭代器。因此,为了允许自定义类为每个循环使用,您需要提供begin()
和end()
函数。这些函数通常重载,返回迭代器或常量迭代器。实现迭代器可能很棘手,尽管使用类似向量的类并不太难
template <typename T>
struct List
{
T* store;
std::size_t size;
typedef T* iterator;
typedef const T* const_iterator;
....
iterator begin() { return &store[0]; }
const_iterator begin() const { return &store[0]; }
iterator end() { return &store[size]; }
const_iterator end() const { return &store[size]; }
...
};
模板
结构列表
{
T*商店;
标准:大小;
typedef T*迭代器;
typedef常量T*常量迭代器;
....
迭代器begin(){return&store[0];}
常量迭代器begin()常量{return&store[0];}
迭代器end(){return&store[size];}
常量迭代器end()常量{return&store[size];}
...
};
实现这些功能后,您可以像上面那样使用基于范围的循环。C++在其语法中没有每个循环的功能。您必须使用C++11或使用模板函数
#包括
#包括
#包括
结构和{
Sum(){Sum=0;}
void运算符()(int n){sum+=n;}
整数和;
};
int main()
{
std::向量nums{3,4,2,9,15,267};
std::cout正如@yngum所建议的,通过在集合上定义begin()
和end()
方法来返回自定义迭代器,您可以让每个
扩展的VC++处理任意集合类型。您的迭代器反过来必须实现必要的接口(解引用运算符、增量运算符等)。我这样做是为了包装遗留代码的所有MFC集合类。这是一项工作,但可以完成。让iterable
为iterable
类型。
那么为了
for (Type x : iterable)
编译时,必须有名为Type
和IType
的类型,并且必须有函数
IType Iterable::begin()
IType Iterable::end()
IType
必须提供以下功能
Type operator*()
void operator++()
bool operator!=(IType)
整个结构对于这样的东西来说是非常复杂的语法
for (IType it = iterable.begin(); it != iterable.end(); ++it) {
Type x = *it;
...
}
如果不使用类型
,则可以使用任何兼容类型(如常量类型
或类型&
),这将产生预期的影响(常量、引用而非副本等)
由于整个扩展是按语法进行的,因此您还可以稍微更改运算符的声明,例如,让*它返回一个引用或让!=根据需要获取一个常量IType&rhs
请注意,如果*表单不返回引用,则不能使用for(Type&x:iterable)
表单(但如果它返回引用,也可以使用复制版本)
还请注意,operator++()
定义了++
运算符的前缀版本——但是,除非您明确定义后缀++
,否则它也将用作后缀运算符。如果您只提供后缀++
,则不会编译ranged for,顺便说一句,它可以声明为operator++(int)
(伪int参数)
最简单的工作示例:
#include <stdio.h>
typedef int Type;
struct IType {
Type* p;
IType(Type* p) : p(p) {}
bool operator!=(IType rhs) {return p != rhs.p;}
Type& operator*() {return *p;}
void operator++() {++p;}
};
const int SIZE = 10;
struct Iterable {
Type data[SIZE];
IType begin() {return IType(data); }
IType end() {return IType(data + SIZE);}
};
Iterable iterable;
int main() {
int i = 0;
for (Type& x : iterable) {
x = i++;
}
for (Type x : iterable) {
printf("%d", x);
}
}
可以用以下宏(
)伪造每个(例如,对于旧C++编译器)的范围
#define ln(l, x) x##l // creates unique labels
#define l(x,y) ln(x,y)
#define for_each(T,x,iterable) for (bool _run = true;_run;_run = false) for (auto it = iterable.begin(); it != iterable.end(); ++it)\
if (1) {\
_run = true; goto l(__LINE__,body); l(__LINE__,cont): _run = true; continue; l(__LINE__,finish): break;\
} else\
while (1) \
if (1) {\
if (!_run) goto l(__LINE__,cont);/* we reach here if the block terminated normally/via continue */ \
goto l(__LINE__,finish);/* we reach here if the block terminated by break */\
} \
else\
l(__LINE__,body): for (T x = *it;_run;_run=false) /* block following the expanded macro */
int main() {
int i = 0;
for_each(Type&, x, iterable) {
i++;
if (i > 5) break;
x = i;
}
for_each(Type, x, iterable) {
printf("%d", x);
}
while (1);
}
(如果编译器甚至没有auto,则使用declspec或pass IType)
输出:
1234500000
正如您所看到的,continue
和break
由于其复杂的构造,可以使用它。
有关创建自定义控件结构的更多C预处理器黑客攻击,请参阅。您可以编写begin()
和end()
成员函数和迭代器类型,使您的类与foreach兼容。您好,您的答案也很好,但遗憾的是,我无法接受2个答案。感谢您提供的链接:D@RicardoPieper请注意,基于范围的for循环仅在最新版本的visual studio(2012)中可用。所以它不会在任何其他编译器/IDE中编译?@RicardoPieper它会在过去几年的任何版本的Clang或gcc中编译(我认为gcc是4.7以上,不确定Clang版本).好的,这对我来说已经足够了,因为我使用VS2012进行编程。我成功地实现了迭代器,非常简单。我认为答案并不完整。您隐式地假设List::iterator具有一些功能(在本例中,您是免费的,因为迭代器是指针。这不是一般情况).迭代器类型的假设是什么?它是运算符++和运算符==。还有其他吗?
#include <stdio.h>
typedef int Type;
struct IType {
Type* p;
IType(Type* p) : p(p) {}
bool operator!=(IType rhs) {return p != rhs.p;}
Type& operator*() {return *p;}
void operator++() {++p;}
};
const int SIZE = 10;
struct Iterable {
Type data[SIZE];
IType begin() {return IType(data); }
IType end() {return IType(data + SIZE);}
};
Iterable iterable;
int main() {
int i = 0;
for (Type& x : iterable) {
x = i++;
}
for (Type x : iterable) {
printf("%d", x);
}
}
0123456789
#define ln(l, x) x##l // creates unique labels
#define l(x,y) ln(x,y)
#define for_each(T,x,iterable) for (bool _run = true;_run;_run = false) for (auto it = iterable.begin(); it != iterable.end(); ++it)\
if (1) {\
_run = true; goto l(__LINE__,body); l(__LINE__,cont): _run = true; continue; l(__LINE__,finish): break;\
} else\
while (1) \
if (1) {\
if (!_run) goto l(__LINE__,cont);/* we reach here if the block terminated normally/via continue */ \
goto l(__LINE__,finish);/* we reach here if the block terminated by break */\
} \
else\
l(__LINE__,body): for (T x = *it;_run;_run=false) /* block following the expanded macro */
int main() {
int i = 0;
for_each(Type&, x, iterable) {
i++;
if (i > 5) break;
x = i;
}
for_each(Type, x, iterable) {
printf("%d", x);
}
while (1);
}
1234500000