The dictionary defines polymorphism as the ability to take on different forms. In C++ polymorphism means multiple definitions for the same function. We have already studied a form of polymorphism in function overloading. This is referred to as ad hoc polymorphism or functional polymorphism.
Polymorphism is implemented when you have (a) derived class(es) containing a member function with the same signature as a base class. A function invoked through a pointer to the base class, will execute the correct implementation regardless of whether the pointer is pointing at a base class object or a derived class object. Functions that behave in this way are called virtual functions. The determination of which function to call is not known at compile-time, so the correct function is selected during execution. This process is called late binding, or dynamic binding. The usual call of a function through an object, is known to the compiler, hence, early binding or static binding.
Non-virtual vs. Virtual Functions
Example 7-9 - Non virtual Functions
This example and the next one demonstrate the difference between a virtual and a non-virtual function.
1 // File: ex7-9.cpp – Inheritance with a non-virtual function
2
3 #include <iostream>
4 using namespace std;
5
6 class B
7 {
8 public:
9 B() { cout << "B ctor called for " << this << endl;}
10 void funk1()
11 { cout << "B::funk1() called for " << this << endl; }
12 void funk2()
13 { cout << "B::funk2() called for " << this << endl; }
14 };
15
16
17 class D : public B
18 {
19 public:
20 D() { cout << "D ctor called for " << this << endl; }
21 void funk1() // Override funk1()
22 { cout << "D::funk1() called for " << this << endl; }
23 };
24 int main(void)
25 {
26 B b;
27 D d;
28 cout << endl;
29
30 b.funk1();
31 d.funk1();
32 cout << endl;
33
34 b.funk2();
35 d.funk2();
36 cout << endl;
37
38 B* pB;
39 pB = &b;
40 pB->funk1();
41 cout << endl;
42
43 pB = &d;
44 pB->funk1();
45 cout << endl;
46
47 cout << "size of b = " << sizeof b << endl;
48 cout << "size of d = " << sizeof d << endl;
49
50 return 0;
51 }****** Output ******
B ctor called for 0012FF7C <- Output from line 26
B ctor called for 0012FF78 <- Output from line 27
D ctor called for 0012FF78 <- Output from line 27
B::funk1() called for 0012FF7C <- Output from line 30
D::funk1() called for 0012FF78 <- Output from line 31
B::funk2() called for 0012FF7C <- Output from line 34
B::funk2() called for 0012FF78 <- Output from line 35
B::funk1() called for 0012FF7C <- Output from line 40
B::funk1() called for 0012FF78 <- Output from line 44
size of b = 1 <- Output from line 47
size of d = 1 <- Output from line 48
Why does a B and a D object have a size of 1?
Example 7-10 - Virtual Functions
This example is the same as the last one, except that funk1() is declared a virtual function. Hence, this program implements polymorphism.
1 // File: ex7-10.cpp – Inheritance with a virtual function
2
3 #include <iostream>
4 using namespace std;
5
6 class B
7 {
8 public:
9 B() { cout << "B ctor called for " << this << endl;}
10 void funk1()
11 { cout << "B::funk1() called for " << this << endl; }
12 virtual void funk2()
13 { cout << "B::funk2() called for " << this << endl; }
14 };
15
16
17 class D : public B
18 {
19 public:
20 D() { cout << "D ctor called for " << this << endl;}
21 void funk1() // Override funk1()
22 { cout << "D::funk1() called for " << this << endl; }
23 virtual void funk2() // Override funk2()
24 { cout << "D::funk2() called for " << this << endl; }
25
26 };
27 int main(void)
28 {
29 B b;
30 D d;
31 cout << endl;
32
33 b.funk1();
34 d.funk1();
35 cout << endl;
36
37 b.funk2();
38 d.funk2();
39 cout << endl;
40
41 B* pB;
42 pB = &b;
43 pB->funk1();
44 pB->funk2();
45 cout << endl;
46
47 pB = &d;
48 pB->funk1();
49 pB->funk2();
50
51 cout << endl;
52
53 cout << "size of b = " << sizeof b << endl;
54 cout << "size of d = " << sizeof d << endl;
55
56 return 0;
57 }****** Output ******
B ctor called for 0012FF7C <- Output from line 29
B ctor called for 0012FF78 <- Output from line 30
D ctor called for 0012FF78 <- Output from line 30
B::funk1() called for 0012FF7C <- Output from line 33
D::funk1() called for 0012FF78 <- Output from line 34
B::funk2() called for 0012FF7C <- Output from line 37
D::funk2() called for 0012FF78 <- Output from line 38
B::funk1() called for 0012FF7C <- Output from line 43
B::funk2() called for 0012FF7C <- Output from line 44
B::funk1() called for 0012FF78 <- Output from line 48
D::funk2() called for 0012FF78 <- Output from line 49
size of b = 4 <- Output from line 53
size of d = 4 <- Output from line 54
Example 7-11 - Virtual Functions
This example illustrates that
- a virtual function does not have to be overridden in the derived class and
- also that you may not execute a derived class function that is not defined in the base class through a base class pointer even if the pointer is pointing at a derived class object.
1 // File: ex7-11.cpp
2 #include <iostream>
3 using namespace std;
4
5 class B {
6 protected:
7 int b;
8 public:
9 B() { cout << "B ctor called for " << this << endl; b = 0; }
10 virtual void virt()
11 { cout << "B::virt() called for " << this << endl; }
12 };
13
14 class D : public B {
15 protected:
16 int d;
17 public:
18 D() { cout << "D ctor called for " << this << endl; d = 0;}
19 void non_virt2()
20 { cout << "D::non_virt2() called for " << this << endl; }
21 };
22
23 int main() {
24 B b; // declare a base object
25 D d; // declare a derived object
26
27 b.virt(); // invoke virt() through a base object
28 d.virt(); // invoke virt() through a derived object
29
30 B* pb; // pb is a pointer to a base class object
31 pb = &b; // pb points to b
32
33 pb->virt(); // invoke virt() through a base pointer
34 // to a base object
35
36 pb = &d; // pb points to d
37 pb->virt(); // invoke virt() through a base pointer
38
39 cout << "size of b = " << sizeof b << endl;
40 cout << "size of d = " << sizeof d << endl;
41 d.non_virt2(); // invoke non_virt2() through derived object
42 // pb->non_virt2(); Error: non_virt2() is not a member of B
43 return 0;
44 }****** Output ******
B ctor called for 0x2488fff2
B ctor called for 0x2488ffec
D ctor called for 0x2488ffec
B::virt() called for 0x2488fff2
B::virt() called for 0x2488ffec
B::virt() called for 0x2488fff2
B::virt() called for 0x2488ffec
size of b = 8
size of d = 12
D::non_virt2() called for 0x2488ffec
Example 7-12 - Virtual Functions
This example shows that
- "virtualness" is passed down to derived classes even if the immediate "parent" class does not name a function as virtual and
- polymorphism may be implemented through references instead of pointers to base objects.
1 // File: ex7-12.cpp
2
3 #include <iostream>
4 using namespace std;
5
6 class person
7 {
8 protected:
9 int data;
10 public:
11 virtual char *WhoAmI() { return "person"; }
12 char *nonVirtualWhoAmI() { return "non_virtual person"; }
13 };
14
15 class child : public person
16 {
17 public:
18 char *WhoAmI() { return "child"; }
19 char *nonVirtualWhoAmI() { return "non_virtual child"; }
20 };
21
22 class grand_child : public child
23 {
24 public:
25 char *WhoAmI() { return "grand_child"; }
26 char *nonVirtualWhoAmI(){ return "non_virtual rand_child"; }
27 };
28
29
30 // non class member function with person& argument
31 void identify_yourself(person& p)
32 {
33 cout << "I am a " << (p.WhoAmI()) << endl;
34 cout << "I am a " << (p.nonVirtualWhoAmI()) << endl;
35 }
36 int main()
37 {
38 person P;
39 child C;
40 grand_child G;
41
42 person* pp;
43 pp = &P;
44 cout << (pp->WhoAmI()) << endl;
45 cout << (pp->nonVirtualWhoAmI()) << endl;
46
47 pp = &C;
48 cout << (pp->WhoAmI()) << endl;
49 cout << (pp->nonVirtualWhoAmI()) << endl;
50
51 pp = &G;
52 cout << (pp->WhoAmI()) << endl;
53 cout << (pp->nonVirtualWhoAmI()) << endl;
54
55 cout << "sizeof(int) = " << sizeof(int) << endl;
56 cout << "sizeof(person) = " << sizeof(person) << endl;
57 cout << "sizeof(child) = " << sizeof(child) << endl;
58 cout << "sizeof(grand_child) = " << sizeof(grand_child) <<endl;
59
60 identify_yourself(P);
61 identify_yourself(C);
62 identify_yourself(G);
63
64 return 0;
65 }****** Output ******
person
non_virtual person
child
non_virtual person
grand_child
non_virtual person
sizeof(int) = 4
sizeof(person) = 8
sizeof(child) = 8
sizeof(grand_child) = 8
I am a person
I am a non_virtual person
I am a child
I am a non_virtual person
I am a grand_child
I am a non_virtual person
Why write a Virtual destructor?
Example 7-13
This example illustrates why you might want to write a virtual destructor.
1 // File: ex7-13.cpp - Why a Virtual destructor?
2
3 #include <iostream>
4 using namespace std;
5
6 class X
7 {
8 public:
9 X(void) { cout << "X constructor called\n"; }
10 ~X(void) { cout << "X destructor called\n"; }
11 };
12
13
14 class A : public X
15 {
16 public:
17 A(void) { cout << "A constructor called\n"; }
18 ~A(void) { cout << "A destructor called\n"; }
19 };
20
21
22 int main(void)
23 {
24 X* ptrX;
25
26 ptrX = new X;
27 delete ptrX;
28
29 cout << endl;
30
31 ptrX = new A;
32 delete ptrX;
33 return 0;
34 }****** Output ******
X constructor called
X destructor called
X constructor called
A constructor called
X destructor called
What's the problem?
Example 7-14
This example shows how to write a virtual destructor. Compare the output with the last example.
1 // File: ex7-14.cpp - Why a Virtual destructor? Here’s why!
2
3 #include <iostream>
4 using namespace std;
5
6 class X
7 {
8 public:
9 X(void) { cout << "X constructor called\n"; }
10 virtual ~X(void) { cout << "X destructor called\n"; }
11 };
12
13
14 class A : public X
15 {
16 public:
17 A(void) { cout << "A constructor called\n"; }
18 ~A(void) { cout << "A destructor called\n"; }
19 };
20
21
22 int main(void)
23 {
24 X* ptrX;
25
26 ptrX = new X;
27 delete ptrX;
28
29 cout << endl;
30
31 ptrX = new A;
32 delete ptrX;
33 return 0;
34 }****** Output ******
X constructor called
X destructor called
X constructor called
A constructor called
A destructor called
X destructor called
Note: it is not necessary to repeat the virtual for the destructor in the derived class.
Non-Virtual, Virtual, and Pure Virtual Functions
The following notes differentiate these three types of class member functions:
Non-Virtual
- This is the default type of class member function. The keyword virtual does not appear in the function prototype.
- Non-virtual functions, as a rule, are not usually overridden in the derived class.
Virtual
- The keyword virtual appears at the beginning of the function prototype in the base class. It doesn't have to be used in derived class function prototypes, but it's not a bad idea to use it.
- Virtual functions, as a rule, are usually overridden in the derived class.
- Virtual functions make polymorphism possible.
Pure Virtual
- The keyword virtual appears at the beginning and = 0 at the end of the function prototype in the base class. The = 0 is not repeated in derived classes unless that class is intended to serve as a base class for other descendent classes.
- Pure virtual functions must be overridden in the derived class, unless, that class is also a base class for other classes.
- Pure virtual functions are not defined in the class in which they are declared as pure vitual.
- The presence of a pure virtual function in a class makes it an abstract class. Abstract classes may not be instantiated.
Abstract Classes and Pure Virtual Functions
The following example is the traditional shape class example, illustrating the abstract base class, shape, with pure vitual functions.
Example 7-15 - Abstract classes and pure virtual functions
1 // File: ex7-15.cpp - Abstract classes
2
3 #include <iostream>
4 #include <cmath>
5 #include <cstdlib>
6 using namespace std;
7
8 const double pi = 3.141592654;
9
10 class shape
11 {
12 protected:
13 double x;
14 double y;
15 public:
16 shape(double,double);
17 void print(void) const;
18 virtual double area(void) const = 0; // pure virtual function
19 virtual double girth(void) const = 0; // pure virtual function
20 };
21
22
23 shape::shape(double c_x, double c_y) : x(c_x),y(c_y) {}
24
25 void shape::print(void) const
26 {
27 cout << '(' << x << ',' << y << ')';
28 }
29
30
31 class square : public shape
32 {
33 private:
34 double side;
35 public:
36 square(double c_x,double c_y, double s);
37 double get_side(void) { return side; }
38 double area(void) const;
39 double girth(void) const;
40 };
41
42 square::square(double c_x, double c_y, double s) : shape(c_x,c_y)
43 {
44 side = s;
45 }
46
47 double square::area(void) const
48 {
49 return side * side;
50 }
51
52 double square::girth(void) const
53 {
54 return 4.*side;
55 }
56
57
58 class triangle : public shape
59 {
60 private:
61 double a,b,c; // length of 3 sides
62 public:
63 triangle(double X,double Y, double A, double B, double C);
64 void print_sides(void);
65 double area(void) const;
66 double girth(void) const;
67 };
68
69 triangle::triangle(double X,double Y,double A,double B,double C)
70 : shape(X,Y)
71 {
72 a = A;
73 b = B;
74 c = C;
75 }
76
77 void triangle::print_sides(void)
78 {
79 cout << a << ' ' << b << ' ' << c;
80 return;
81 }
82
83 double triangle::area(void) const
84 {
85 double s = (a + b + c) / 2.; // semiperimeter
86 return sqrt(s*(s-a)*(s-b)*(s-c));
87 }
88
89 double triangle::girth(void) const
90 {
91 return a+b+c;
92 }
93
94
95 class circle : public shape
96 {
97 private:
98 double radius;
99 public:
100 circle(double c_x, double c_y, double r);
101 double get_radius(void) { return radius; }
102 double area(void) const;
103 double girth(void) const;
104 };
105
106 circle::circle(double c_x, double c_y, double r) : shape(c_x,c_y)
107 {
108 radius = r;
109 }
110
111 double circle::area(void) const
112 {
113 return pi*radius*radius;
114 }
115
116 double circle::girth(void) const
117 {
118 return 2.*pi*radius;
119 }
120
121
122 int main(void)
123 {
124 // shape sh(6,7); can't create instance of abstract class
125 circle c(3,4,5);
126 cout << "circle c - center: ";
127 c.print();
128 cout << " radius = " << c.get_radius();
129 cout << " area = " << c.area();
130 cout << " circumference = " << c.girth() << endl;
131
132 square s(5.,2.,1.);
133 cout << "square s - center: ";
134 s.print();
135 cout << " side = " << s.get_side();
136 cout << " area = " << s.area();
137 cout << " perimeter = " << s.girth() << endl;
138
139 triangle t(0,0,3,4,5);
140 cout << "triangle t - center: ";
141 t.print();
142 cout << " sides = ";
143 t.print_sides();
144 cout << " area = " << t.area();
145 cout << " perimeter = " << t.girth() << endl;
146
147 cout << "sizeof(double)=" << sizeof(double) << endl;
148 cout << "sizeof(shape)=" << sizeof(shape) << endl;
149 cout << "sizeof(square)=" << sizeof(square) << endl;
150 cout << "sizeof(triangle)=" << sizeof(triangle) << endl;
151 cout << "sizeof(circle)=" << sizeof(circle) << endl;
152
153
154 return 0;
155 }****** Output ******
circle c - center: (3,4) radius = 5 area = 78.5398 circumference = 31.4159
square s - center: (5,2) side = 1 area = 1 perimeter = 4
triangle t - center: (0,0) sides = 3 4 5 area = 6 perimeter = 12
sizeof(double)=8
sizeof(shape)=24
sizeof(square)=32
sizeof(triangle)=48
sizeof(circle)=32
Example 7-16 - Life
The following example is a practical application which make use of polymorphism and an abstract class.
1 // File: ex7-16.cpp - Life and polymorphism
2
3 #include <iostream>
4 #include <cstdlib>
5 using namespace std;
6
7 enum LifeForm {VACANT, WEED, RABBIT, HAWK};
8
9 const int GridSize = 10;
10 const int Cycles = 10;
11 const int NumberLifeForms = 4;
12 const int HawkLifeExpectancy = 8;
13 const int HawkOvercrowdingLimit = 3;
14 const int RabbitLifeExpectancy = 3;
15
16 class Grid;
17
18 class LivingThing {
19 protected:
20 int x,y;
21 void AssessNeighborhood(const Grid& G, int sm[]);
22 public:
23 LivingThing(int _x, int _y): x(_x), y(_y) {}
24 virtual LifeForm WhoAmI() = 0;
25 virtual LivingThing* next(const Grid& G) = 0;
26 };
27
28 class Grid {
29 friend void LivingThing::AssessNeighborhood(const Grid& G,
30 int sm[]);
31 private:
32 LivingThing* cell[GridSize][GridSize];
33 public:
34 Grid();
35 ~Grid() { if (cell[1][1]) release();}
36 void update(Grid&);
37 void release();
38 void print() const;
39 };
40
41 /* This function counts the number of each LivingThing thing in
42 the neighborhood. A neighborhood is a square and the 8
43 adjacent squares on each side of it */
44 void LivingThing::AssessNeighborhood(const Grid& G, int count[]){
45 int i, j;
46 count[VACANT] = count[WEED] = count[RABBIT] = count[HAWK] = 0;
47 for (i = -1; i <= 1; ++i)
48 for (j = -1; j <= 1; ++j)
49 count[G.cell[x+i][y+j] -> WhoAmI()]++;
50 }
51 class Vacant:public LivingThing
52 {
53 public:
54 Vacant(int _x, int _y):LivingThing(_x,_y) {}
55 LifeForm WhoAmI() {return (VACANT);}
56 LivingThing* next(const Grid& G);
57 };
58
59 class Weed : public LivingThing
60 {
61 public:
62 Weed(int _x, int _y): LivingThing(_x,_y){}
63 LifeForm WhoAmI() {return (WEED);}
64 LivingThing* next(const Grid& G);
65 };
66
67 class Rabbit : public LivingThing
68 {
69 protected:
70 int age;
71 public:
72 Rabbit(int x, int y, int a = 0) : LivingThing(x,y), age(a) {}
73 LifeForm WhoAmI() { return (RABBIT); }
74 LivingThing* next(const Grid& G);
75 };
76
77 class Hawk : public LivingThing
78 {
79 protected:
80 int age;
81 public:
82 Hawk(int x, int y, int a = 0): LivingThing(x,y), age(a){}
83 LifeForm WhoAmI() {return (HAWK);}
84 LivingThing* next(const Grid& G);
85 };
86 // This function determines what will be in an Vacant square in
87 // the next cycle
88 LivingThing* Vacant::next(const Grid& G)
89 {
90 int count[NumberLifeForms];
91 AssessNeighborhood(G,count);
92
93 // If there is more than one Rabbit in the neighborhood, a new
94 // Rabbit is born.
95 if (count[RABBIT] > 1) return (new Rabbit(x,y));
96
97 // otherwise, if there is more than one Hawk, a Hawk will be born
98 else if (count[HAWK] > 1) return (new Hawk(x, y));
99
100 // else, if there is a Weed in the neighborhood, a Weed will grow
101 else if (count[WEED]) return (new Weed(x, y));
102
103 // otherwise the square will remain Vacant
104 else return (new Vacant(x, y));
105 }
106
107
108 // If there is more Weeds than Rabbits, then new Weed will grow,
109 // otherwise Vacant
110 LivingThing* Weed::next(const Grid& G)
111 {
112 int count[NumberLifeForms];
113 AssessNeighborhood(G, count);
114 if (count[WEED] > count[RABBIT]) return (new Weed(x, y));
115 else return (new Vacant(x, y));
116 }
117
118
119 /* The Rabbit dies if:
120 there's more Hawks in the neighborhood than Rabbits
121 not enough to eat
122 or if it's too old
123 otherwise the Rabbit ages */
124 LivingThing* Rabbit::next(const Grid& G)
125 {
126 int count[NumberLifeForms];
127 AssessNeighborhood(G, count);
128 if (count[HAWK] >= count[RABBIT] ) return (new Vacant(x, y));
129 else if (count[RABBIT] >count[WEED]) return (new Vacant(x, y));
130 else if (age > RabbitLifeExpectancy) return (new Vacant(x, y));
131 else return (new Rabbit(x,y, age + 1));
132 }
133 // Hawk die of overcrowding, starvation, or old age
134 LivingThing* Hawk::next(const Grid& G)
135 {
136 int count[NumberLifeForms];
137 AssessNeighborhood(G, count);
138 if (count[HAWK]>HawkOvercrowdingLimit)
139 return (new Vacant(x,y));
140 else if (count[RABBIT] < 1) return (new Vacant(x,y));
141 else if (age > HawkLifeExpectancy) return (new Vacant (x, y));
142 else return (new Hawk(x, y, age + 1));
143 }
144
145 Grid::Grid()
146 {
147 LifeForm creature;
148 int i, j;
149 for (i = 0; i < GridSize; i++)
150 for (j = 0; j < GridSize; j++)
151 {
152 if (i==0 || i==GridSize-1 || j==0 || j==GridSize-1)
153 creature = VACANT;
154 else
155 creature = LifeForm(rand() % NumberLifeForms);
156 switch (creature)
157 {
158 case HAWK:cell[i][j] = new Hawk(i,j); break;
159 case RABBIT: cell[i][j] = new Rabbit(i,j); break;
160 case WEED:cell[i][j] = new Weed(i,j);break;
161 case VACANT: cell[i][j] = new Vacant(i,j);
162 }
163 }
164 }
165
166 void Grid::release()
167 {
168 int i, j;
169 for (i = 1; i < GridSize - 1; ++i)
170 for (j = 1; j < GridSize - 1; ++j) delete cell[i][j];
171 cell[1][1] = 0;
172 }
173
174 void Grid::update(Grid& old)
175 {
176 int i, j;
177 for (i = 1; i < GridSize - 1; ++i)
178 for (j = 1; j < GridSize - 1; ++j)
179 cell[i][j] = old.cell[i][j] -> next(old);
180 }
181 void Grid::print() const
182 {
183 LifeForm creature;
184 int i, j;
185 for (i = 1; i < GridSize - 1; i++)
186 {
187 for (j = 1; j < GridSize - 1; j++)
188 {
189 creature = cell[i][j]->WhoAmI();
190 switch (creature)
191 {
192 case HAWK: cout << "H"; break;
193 case RABBIT: cout << "R"; break;
194 case WEED:cout << "W"; break;
195 case VACANT:cout << "0";
196 }
197 }
198 cout << endl;
199 }
200 cout << endl;
201 return;
202 }
203
204
205 int main(void)
206 {
207 Grid G1, G2;
208 G1.print();
209
210 for (int i = 1; i <= Cycles; i++)
211 {
212 cout << "Cycle " << i << endl;
213 if (i % 2)
214 {
215 G2.update(G1);
216 G2.print();
217 G1.release();
218 }
219 else
220 {
221 G1.update(G2);
222 G1.print();
223 G2.release();
224 }
225 }
226 return 0;
227 }****** Output ******
RRRR0WHH
0R0RHH00
0WHHHWRW
RW0HH0WH
HWRRHHW0
W0R00HR0
HHH0H00R
HRRWWHRW
Cycle 1
0000RW00
R0R000HH
R0H00W0W
0WR00HWH
H00000WW
WR0RH00R
H0HR0RR0
H00WWH00
Cycle 2
0R0RR0HH
0R0RWW00
0RHRWWHW
W000W0W0
HRRRHHWW
00R0HRRR
HHH0R00R
0HWW0HR0
Cycle 3
R0R00W00
R0R00WHH
R0HRWW0W
0RRRWHWW
H000HH0W
HR0RH000
00HR0RR0
H0WWWH0R
Cycle 4
0R0RWWHH
0R0RWW00
0RH0WWHW
R000W0WW
HRRR00HW
H0R0HRRW
HHH0R00R
0HWW0HR0
Cycle 5
R0RRWW00
R0RRWWHH
R0HWWW0W
0RRRWHWW
H000RRHW
0R0RH000
00HR0RR0
H0WWWH0R
Cycle 6
0R00WWHH
0R0RWW00
0RH0WWHW
R00RWHWW
HRRR00HW
00R0HRRW
0HH0R00R
0HWW0HR0
Cycle 7
R0RWWW00
R0R0WWHH
R0HRWW0W
0RR0W0WW
H000RRHW
HR0RH000
HHHR0RR0
H0WWWH0R
Cycle 8
0R0WWWHH
0R0RWW00
0RHRWWHW
R00R0RWW
HRRR00HW
00R0HRRW
00H0R00R
0HWW0HR0
Cycle 9
R0RWWW00
R0RRWWHH
R0H00WHW
0RR0R0WW
H000RRHW
0R0RH000
0HHR0RR0
00WWWH0R
沒有留言:
張貼留言