This algorithm is particularly suitable to be the basis for a nice example of Object Oriented Programming. We will see how to program it in C++. For more details, see also the book of Sethi, Section 7.5.

The general idea is to create dynamically new objects, one for each prime number which is generated, and to let each of these object be responsible for eliminating (filtering away) numbers which are not prime. The simplest organization is to have all these objects connected in a chain, and new numbers (generated by an object at the beginning of the chain) flowing through the chain. The picture below illustrates the organization of the objects and the flow of data:

------------- | Counter | generates natural numbers ------------- || | flow of data \/ V ------------- | Filter 2 | eliminates numbers that are multiples of 2 ------------- || \/ ------------- | Filter 3 | eliminates numbers that are multiples of 3 ------------- || \/ ------------- | Filter 5 | eliminates numbers that are multiples of 5 ------------- || \/ ------------- | Filter 7 | eliminates numbers that are multiples of 7 ------------- ...The design of the actual program will depend also on how the control is organized, namely how the various objects get activated. In general we can distinguish two main possibilities:

**Single-thread of control**: only one object is active at a time**Multi-threads of control**: many objects are (potentially) active at the same time.

**Demand driven**: Each component is activated by "demanding" from it the production of a new datum. More precisely, each component is activated by the next component in the chain. (The last one is activated by some external entity, for instance by a print command.) Thus the flow of control goes in the direction*opposite*to the flow of data.**Data driven**: Each component is activated by sending to it a new datum. More precisely, each component is activated by the previous component in the chain. (The first one keeps active by repeating some instructions in a loop.) Thus the flow of control goes in the*same*direction as the flow of data.

- a Counter, whose task is to produce,
*on-demand*the next natural number, - a Filter for each prime number k generated so far,
whose task is to generate,
*on-demand*, a new number candidate to be a prime number. When the filter receives a request from the next object in the chain, it repeatedly asks the previous object in the chain for new numbers, until it gets a number n which is not a multiple of k. (or, equivalently, of which k is not a factor). Such number n is returned, and all the others are eliminated. - a Sieve, whose task is to generate,
*on-demand*, a new prime number n (obtained by asking the last filter in the chain) and create a filter with factor n between itself and the last filter in the chain.

In this kind of architecture, each object must know the
identity of the previous object in the chain (called
*source* by Sethi). Thus we have a structure like the following
(after the production of 5). The arrows indicate the pointers
between objects.

------------- | 6 | Counter. Will generate 6 next ------------- ^ | ------+------ | | | | | ------------- | 2 | Filter with factor 2 ------------- ^ | ------+------ | | | | | ------------- | 3 | Filter with factor 3 ------------- ^ | ------+------ | | | | | ------------- | 5 | Filter with factor 5 ------------- ^ ^ | | flow of control ------+------ | | | Sieve | | -------------Note that, at the beginning, there are only two objects: Sieve and Counter. This means that the source of Sieve is originally a Counter, and later it becomes a Filter. One advantage of using Object-Oriented technology is that we can treat the two situations uniformly. This can be done by using a basic class Item (following Sethi's terminology), of which all the other classes (Counter, Filter, and Sieve) will be subclasses. The main purpose of Item is to contain a declaration of a metod

Another advantage of OO is that we can declare a single destructor
method in Item and have it effective, by* inheritance*,
in all the subclasses.

We are now ready to give the code. This is essentially the same code defined in Sethi, with a few additions to illustrate its possible use.

/* Eratosthenes' Sieve */ /* Demand driven model */ #include <iostream.h> class Item { protected: Item *source; public: virtual int out() {} // to be overriden in the subclasses ~Item() { delete source; } }; class Counter: public Item { int value; public: int out() { return value++; } Counter() { source = 0; value = 2; } }; class Filter: public Item { int factor; public: int out() { int n; n = source->out(); while(!(n%factor)) { n = source->out(); } return n; } Filter(Item *src, int f){ source = src; factor = f; } }; class Sieve :public Item{ public: int out() { int n = source->out(); source = new Filter(source, n); return n; } Sieve(Item *src){source =src;} }; main() { Counter *g = new Counter(); Sieve *s = new Sieve(g); char a; cout << "Do you want the first prime number? (y/n) "; cin >> a; while (a=='y'){ cout << s->out() << '\n'; cout << "Do you want the next prime number? (y/n) "; cin >> a; }; delete s; }

- a Counter, whose task is to produce the sequence of natural numbers,
- a Filter for each prime number k generated so far, whose task is to eliminate the numbers (received from previous component in the chain) which are multiples of k. The last filter in the chain also creates the next filter.

In this kind of architecture, each object must know the
identity of the next object in the chain, which we will call
*destination* by Sethi). Thus we have a structure like the following
(after the production of 5). The arrows indicate the pointers
between objects.

------------- | 6 | Counter. Will generate 6 next ------------- | | | | | ------+------ | | flow of control V V ------------- | 2 | Filter with factor 2 ------------- | | | | | ------+------ | V ------------- | 3 | Filter with factor 3 ------------- | | | | | ------+------ | V ------------- | 5 | Filter with factor 5 ------------- | / | | / | -------------

We are now ready to give the code.

/* Eratosthenes' Sieve */ /* Data driven model */ #include <iostream.h> class Item { protected: Item* destination; public: ~Item(){ delete destination; } virtual void in(int n){} // to be overriden in the subclasses }; class Filter: public Item { int factor; public: Filter(int f){ factor = f; destination = NULL; } void in(int n) { if (n%factor == 0) return; if (destination != NULL) destination->in(n); else { destination = new Filter(n); cout << "The next prime number is " << n << '\n'; } } }; class Counter: public Item { int value; int max; public: Counter(int m){ max = m; } void start(){ if (max < 2) return; destination = new Filter(2); cout << "The first prime number is " << 2 << '\n'; value = 3; while (value <= max) destination->in(value++); } }; class EratostenesSieve{ int max; Counter* gen; public: EratostenesSieve(int m){ max = m; } void start(){ gen = new Counter(max); gen->start(); } ~EratostenesSieve(){ delete gen; } }; void main() { int max; cout << "Please input the max number to be generated" << '\n'; cin >> max; EratostenesSieve es(max); es.start(); cout << "End\n"; }