容器中的对象做的大部分的工作是对所有这些对象应用某个运算扩展模板
需要保持追踪它的对象的类
这样我们可以知道这些对象被适当地销毁掉
//: C06:Counted.h
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// An object that keeps track of itself.
#ifndef COUNTED_H
#define COUNTED_H
#include <vector>
#include <iostream>
class Counted {
static int count;
char* ident;
public:
Counted(char* id) : ident(id) { ++count; }
~Counted() {
std::cout << ident << " count = "
<< --count << std::endl;
}
};
class CountedVector : public std::vector<Counted*> {
public:
CountedVector(char* id) {
for(int i = 0; i < 5; i++)
push_back(new Counted(id));
}
};
#endif // COUNTED_H ///:~
//: C06:Counted.cpp {O}
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include "Counted.h"
int Counted::count = 0;
///:~
class Counted对已创建的Counted对象的个数保存一个静态的计数
并且当这些对象被销毁时通知用户
CountedVector由 vector<Counted*>派生而来
并且在构造函数中创建一些Counted对象
处理每个想要的char*
//: C06:ForEach.cpp {-mwcc}
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Use of STL for_each() algorithm.
//{L} Counted
#include <algorithm>
#include <iostream>
#include "Counted.h"
using namespace std;
// Function object:
template<class T> class DeleteT {
public:
void operator()(T* x) { delete x; }
};
// Template function:
template<class T> void wipe(T* x) { delete x; }
int main() {
CountedVector B("two");
for_each(B.begin(), B.end(), DeleteT<Counted>());
CountedVector C("three");
for_each(C.begin(), C.end(), wipe<Counted>);
getchar();
} ///:~
输出
two count = 4
two count = 3
two count = 2
two count = 1
two count = 0
three count = 4
three count = 3
three count = 2
three count = 1
three count = 0
这里有一些事情需要反复多次去做
可以创建一个算法用delete来删除容器中所有的指针
可以使用transform完成这项工作
//: C06:Transform.cpp {-mwcc}
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Use of STL transform() algorithm.
//{L} Counted
#include <iostream>
#include <vector>
#include <algorithm>
#include "Counted.h"
using namespace std;
template<class T> T* deleteP(T* x) { delete x; return 0; }
template<class T> struct Deleter {
T* operator()(T* x) { delete x; return 0; }
};
int main() {
CountedVector cv("one");
transform(cv.begin(), cv.end(), cv.begin(),
deleteP<Counted>);
CountedVector cv2("two");
transform(cv2.begin(), cv2.end(), cv2.begin(),
Deleter<Counted>());
getchar();
} ///:~
输出
one count = 4
one count = 3
one count = 2
one count = 1
one count = 0
two count = 4
two count = 3
two count = 2
two count = 1
two count = 0
这里显示了两种方法
使用模板函数或模板化的函数对象
在调用transform()后
vector包含5个空指针
更安全因为用它对任何副本delete都是无效
考虑一个简单的存货清单模型
每个Inventory对象包含它所代表的产品类型
该产品的数量以及每种产品的价格
//: C06:Inventory.h
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#ifndef INVENTORY_H
#define INVENTORY_H
#include <iostream>
#include <cstdlib>
using std::rand;
class Inventory {
char item;
int quantity;
int value;
public:
Inventory(char it, int quant, int val)
: item(it), quantity(quant), value(val) {}
// Synthesized operator= & copy-constructor OK
char getItem() const { return item; }
int getQuantity() const { return quantity; }
void setQuantity(int q) { quantity = q; }
int getValue() const { return value; }
void setValue(int val) { value = val; }
friend std::ostream& operator<<(
std::ostream& os, const Inventory& inv) {
return os << inv.item << ": "
<< "quantity " << inv.quantity
<< ", value " << inv.value;
}
};
// A generator:
struct InvenGen {
Inventory operator()() {
static char c = 'a';
int q = rand() % 100;
int v = rand() % 500;
return Inventory(c++, q, v);
}
};
#endif // INVENTORY_H ///:~
成员函数取得产品项目的名称
取得并确定相应的数量和价格
operator<<向ostream打印出Inventory对象
用一个发生器来创建这些对象
为了找出产品项目的总数及全部价值
可以使用含有总计数数据成员的for_each()来创建一个函数对象
//: C06:CalcInventory.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// More use of for_each().
#include <algorithm>
#include <ctime>
#include <vector>
#include "Inventory.h"
#include "PrintSequence.h"
using namespace std;
// To calculate inventory totals:
class InvAccum {
int quantity;
int value;
public:
InvAccum() : quantity(0), value(0) {}
void operator()(const Inventory& inv) {
quantity += inv.getQuantity();
value += inv.getQuantity() * inv.getValue();
}
friend ostream&
operator<<(ostream& os, const InvAccum& ia) {
return os << "total quantity: " << ia.quantity
<< ", total value: " << ia.value;
}
};
int main() {
vector<Inventory> vi;
srand(time(0)); // Randomize
generate_n(back_inserter(vi), 15, InvenGen());
print(vi.begin(), vi.end(), "vi");
InvAccum ia = for_each(vi.begin(),vi.end(), InvAccum());
cout << ia << endl;
getchar();
} ///:~
输出
vi:
a: quantity 96, value 94
b: quantity 62, value 316
c: quantity 46, value 172
d: quantity 67, value 178
e: quantity 13, value 103
f: quantity 97, value 144
g: quantity 96, value 187
h: quantity 18, value 41
i: quantity 93, value 297
j: quantity 83, value 418
k: quantity 70, value 377
l: quantity 91, value 150
m: quantity 0, value 392
n: quantity 92, value 219
o: quantity 66, value 416
total quantity: 990, total value: 232410
InvAccum的operator()有一个参数
是for_each()要求的
当for_each()遍历某个范围时
获取该范围的每一个对象并将其传递给InvAccum::operator()
//: C06:TransformNames.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// More use of transform().
#include <algorithm>
#include <cctype>
#include <ctime>
#include <vector>
#include "Inventory.h"
#include "PrintSequence.h"
using namespace std;
struct NewImproved {
Inventory operator()(const Inventory& inv) {
return Inventory(toupper(inv.getItem()),
inv.getQuantity(), inv.getValue());
}
};
int main() {
vector<Inventory> vi;
srand(time(0)); // Randomize
generate_n(back_inserter(vi), 15, InvenGen());
print(vi.begin(), vi.end(), "vi");
transform(vi.begin(),vi.end(),vi.begin(),NewImproved());
print(vi.begin(), vi.end(), "vi");
getchar();
} ///:~
市场上的交易决定将所有的产品名称改为大写
使得看上去与 新的、改进的产品一样
做调研并且决定用新的产品名称来进行促销
所以不使用for_each(),而是使用transform()
输出
vi:
a: quantity 5, value 364
b: quantity 89, value 272
c: quantity 18, value 339
d: quantity 56, value 440
e: quantity 10, value 343
f: quantity 31, value 195
g: quantity 60, value 76
h: quantity 93, value 67
i: quantity 9, value 363
j: quantity 45, value 169
k: quantity 67, value 117
l: quantity 0, value 332
m: quantity 18, value 26
n: quantity 83, value 87
o: quantity 23, value 340
vi:
A: quantity 5, value 364
B: quantity 89, value 272
C: quantity 18, value 339
D: quantity 56, value 440
E: quantity 10, value 343
F: quantity 31, value 195
G: quantity 60, value 76
H: quantity 93, value 67
I: quantity 9, value 363
J: quantity 45, value 169
K: quantity 67, value 117
L: quantity 0, value 332
M: quantity 18, value 26
N: quantity 83, value 87
O: quantity 23, value 340
结果范围与输入范围相同
即在适当的位置执行转换
现在假设销售部门需要产生一个特价清单
对每种商品有不同的折扣
原始的清单必须原样保留
并且需要产生任意数量的特价清单
//: C06:SpecialList.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Using the second version of transform().
#include <algorithm>
#include <ctime>
#include <vector>
#include "Inventory.h"
#include "PrintSequence.h"
using namespace std;
struct Discounter {
Inventory operator()(const Inventory& inv,
float discount) {
return Inventory(inv.getItem(), inv.getQuantity(),
int(inv.getValue() * (1 - discount)));
}
};
struct DiscGen {
float operator()() {
float r = float(rand() % 10);
return r / 100.0;
}
};
int main() {
vector<Inventory> vi;
srand(time(0)); // Randomize
generate_n(back_inserter(vi), 15, InvenGen());
print(vi.begin(), vi.end(), "vi");
vector<float> disc;
generate_n(back_inserter(disc), 15, DiscGen());
print(disc.begin(), disc.end(), "Discounts:");
vector<Inventory> discounted;
transform(vi.begin(),vi.end(), disc.begin(),
back_inserter(discounted), Discounter());
print(discounted.begin(), discounted.end(),"discounted");
getchar();
} ///:~
输出
vi:
a: quantity 6, value 177
b: quantity 93, value 373
c: quantity 87, value 150
d: quantity 89, value 275
e: quantity 49, value 277
f: quantity 23, value 247
g: quantity 20, value 242
h: quantity 88, value 39
i: quantity 64, value 316
j: quantity 31, value 250
k: quantity 17, value 71
l: quantity 8, value 315
m: quantity 4, value 126
n: quantity 57, value 254
o: quantity 72, value 490
Discounts::
0.06
0.07
0.02
0.01
0.05
0.03
0.04
0.04
0.02
0.07
0.06
0.06
0.01
0.08
0.07
discounted:
a: quantity 6, value 166
b: quantity 93, value 346
c: quantity 87, value 147
d: quantity 89, value 272
e: quantity 49, value 263
f: quantity 23, value 239
g: quantity 20, value 232
h: quantity 88, value 37
i: quantity 64, value 309
j: quantity 31, value 232
k: quantity 17, value 66
l: quantity 8, value 296
m: quantity 4, value 124
n: quantity 57, value 233
o: quantity 72, value 455
给定一个Inventory对象和一个折扣比率
Discounter函数对象产生一个新的含折扣价格Inventory对象
DiscGen函数对象仅产生随机的从1%到10%之间的折扣值用来进行测试