Using Inheritance

Im trying to show a few box objects using inheritance which adds a few new features such as type of material and the sum of the dimensions. I cant get it to compile. What am I missing/doing wrong. I appreciate any help, thanks.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include<iostream>
#include<cmath>
#include<iomanip>
#include<string>
#include<fstream>
using namespace std;

ofstream outAnswer;

enum color{blue, red , green,black};			//color data type for box
enum material{metal, wood, plastic};
class BOX								//class definition
{
public:
	
	BOX (double, double, double, double, double, int);		//contructor function
		~BOX();														//destructr function
		void set_size( double, double, double, double, double,int);		// changes l,w,h,th, wt,color
		double calc_area();											//for area
		double calc_volume();										//for volume
		void print_report();										// prints report of box

protected:								// Member variables
	double length;
	double width;
	double height;
	double thickness;
	double weight;
	int color;
};

BOX::BOX (double l, double w, double h, double th, double wt, int c){		//constuctor
	length=l;
	width=w;
	height=h;
	thickness=th;
	weight=wt;
	color=c;
}

BOX::~BOX()														//destuctor
{
	outAnswer << " Destroying contents of BOX object" << endl;
}

void BOX::set_size (double l, double w, double h, double th, double wt, int c)	//Changes values for variables
{
	length=l;
	width=w;
	height=h;
	thickness=th;
	weight=wt;
	color=c;
	string colorname;
	
	switch (color){				// switch statement used to print out color of box
	case 0:
		colorname="blue";
		break;
	case 1:
		colorname="red";
		break;
	case 2:
		colorname="green";
		break;
	case 3:
		colorname="black";
	}
	outAnswer << "	 Size has been reset to " << length << " x " << width << " x " << height 
		<< endl << "	 Thickness = " << thickness << endl << "	 Weight = " << weight << endl << "	 Color: " 
		<< colorname << endl;
}

double BOX::calc_area()			//Calculates the area
{
	return (2*(length*width)+2*(height*length)+2*(height*width));
}

double BOX::calc_volume()		// Calculates the volume
{
	return (length*width*height);
}

void BOX::print_report()		// Prints out report of the box
{
	string colorname;
	switch (color){				// switch statement used to printout color of box
	case 0:
		colorname="blue";
		break;
	case 1:
		colorname="red";
		break;
	case 2:
		colorname="green";
		break;
	case 3:
		colorname="black";
	}

	outAnswer << "	 L x W x H = " << length << " x " << width << " x " << height << " , V = " << calc_volume() << endl << "	 Area = " <<
		calc_area() << endl << "	 Thickness = " << thickness << endl << "	 Weight = " << weight  <<  endl << "	 Color: "
		<< colorname << endl;
}

class BETTERBOX:BOX{
public:
	BETTERBOX( int);
	void exceed();
	double sumdim();
	void printreport();
	void setsize( int);
	char ex;
	int material;
};







double BETTERBOX::sumdim()
{
	return (length +width+ height);
}

void BETTERBOX::exceed()
{
	if ((length + width + height) > 65 )
		ex= 'y';
	else
		ex= 'n';
}
void BETTERBOX::printreport()
{
	
	string matname;
	
	
	switch (material)
	{				
	case 0:
		matname="metal";
		break;
	case 1:
		matname="wood";
		break;
	case 2:
		matname="plastic";
	}

	outAnswer << "Sum of the dimensions: " << sumdim() << endl  << " Dimensions exeeed 65: "<< ex << endl << " Material: " << matname << endl;
}

void BETTERBOX::setsize (int m )
{
	
	string matname;


	switch (material){				
	case 0:
		matname="metal";
		break;
	case 1:
		matname="wood";
		break;
	case 2:
		matname="plastic";
	}
	
	
	outAnswer << " Material: " << matname << endl;
	
}
int main()
{
	outAnswer.open("Assignment6.txt");			//Outputs to text file
	

	outAnswer.setf(ios::fixed, ios:: floatfield);  // set up floating point capability
	outAnswer.setf(ios::showpoint);                // set up floating point capability
	outAnswer << setprecision(2);					// decimal up to two places

	BOX Bob (7.5, 2.75, 1.8, 0.1, 33.5, blue );						//First box changing height
		outAnswer << " For Box named Bob: " << endl;
		Bob.print_report();
		Bob.set_size(7.5,2.75, 0.75,0.1,33.5, blue);
		Bob.print_report();

	BOX John (45.0, 32.0, 6.33, 0.15, 530.0, red);					//Second box changing length and thickness
		outAnswer << " For Box named John: " << endl;
		John.print_report();
		John.set_size(11.0, 32.0, 6.33, 0.23, 530.0, green);
		John.print_report();
	
	BOX Dan (60.0, 30.0, 20.0, 0.80,400.0, black );
	BETTERBOX Dan1( wood);											// Third box 
		outAnswer << " For Better Box named Dan: " << endl;
		Dan.print_report();
		Dan1.printreport();
		Dan.set_size( 30.0, 15.5, 10.0,  0.40, 250.0, blue);
		Dan1.setsize(wood);
		Dan.print_report();
		Dan1.printreport();



		outAnswer << "Thanks and goodbye" << endl;
		
		
	
		return 0;

}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include<iostream>
#include<cmath>
#include<iomanip>
#include<string>
#include<fstream>
using namespace std;

ofstream outAnswer;

enum color{blue, red , green,black};	 //color data type for box
enum material{metal, wood, plastic};
class BOX	 //class definition
{
public:

				BOX (double, double, double, double, double, int);	 //contructor function
				~BOX();	 //destructr function
				 void set_size( double, double, double, double, double,int);	 // changes l,w,h,th, wt,color
				 double calc_area();	 //for area
				 double calc_volume();	 //for volume
				 void print_report();	 // prints report of box

	protected:	 // Member variables
				double length;
				double width;
				double height;
				double thickness;
				double weight;
				int color;
};

BOX::BOX (double l, double w, double h, double th, double wt, int c)
	{	 //constuctor
		length=l;
		width=w;
		height=h;
		thickness=th;
		weight=wt;
		color=c;
}

BOX::~BOX()	 //destuctor
{
		outAnswer << " Destroying contents of BOX object" << endl;
}

void BOX::set_size (double l, double w, double h, double th, double wt, int c)	//Changes values for variables
{
			length=l;
			width=w;
			height=h;
			thickness=th;
			weight=wt;
			color=c;
			string colorname;

			switch (color)
				{	 // switch statement used to print out color of box
						case 0:
						colorname="blue";
						break;
						case 1:
						colorname="red";
						break;
						case 2:
						colorname="green";
						break;
						case 3:
						colorname="black";
			}
			outAnswer.open("text.txt");
			outAnswer << "	 Size has been reset to " << length << " x " << width << " x " << height 
<< endl << "	 Thickness = " << thickness << endl << "	 Weight = " << weight << endl << "	 Color: " 
<< colorname << endl;
			outAnswer.close();
}

double BOX::calc_area()	 //Calculates the area
{
return (2*(length*width)+2*(height*length)+2*(height*width));
}

double BOX::calc_volume()	 // Calculates the volume
{
return (length*width*height);
}

void BOX::print_report()	 // Prints out report of the box
{
string colorname;
switch (color){	 // switch statement used to printout color of box
case 0:
colorname="blue";
break;
case 1:
colorname="red";
break;
case 2:
colorname="green";
break;
case 3:
colorname="black";
}
outAnswer.open("text.txt", ofstream::in | ofstream::out | ofstream::app);
outAnswer << "	 L x W x H = " << length << " x " << width << " x " << height << " , V = " << calc_volume() << endl << "	 Area = " <<
calc_area() << endl << "	 Thickness = " << thickness << endl << "	 Weight = " << weight << endl << "	 Color: "
<< colorname << endl;
outAnswer.close();
}

class BETTERBOX:BOX
	{
		public:
				BETTERBOX( int);
				void exceed();
				double sumdim();
				void printreport();
				void setsize( int);
				char ex;
				int material;
};
double BETTERBOX::sumdim()
{
		return (length +width+ height);
}

void BETTERBOX::exceed()
{
		if ((length + width + height) > 65 )
			ex= 'y';
		else
			ex= 'n';
}
void BETTERBOX::printreport()
{

				string matname;

				switch (material)
				{	
				case 0:
					matname="metal";
				break;
				case 1:
					matname="wood";
				break;
				case 2:
					matname="plastic";
				}
				outAnswer.open("text.txt", ofstream::in | ofstream::out | ofstream::app);
				outAnswer << "Sum of the dimensions: " << sumdim() << endl << " Dimensions exeeed 65: "<< ex << endl << " Material: " << matname << endl;
				outAnswer.close();
}

void BETTERBOX::setsize (int m )
{

		string matname;

		material = m;
		switch (m)
			{	
				case 0:
					matname="metal";
				break;
				case 1:
					matname="wood";
				break;
				case 2:
					matname="plastic";
		}

		outAnswer.open("text.txt", ofstream::in | ofstream::out | ofstream::app);
		outAnswer << " Material: " << matname << endl;
		outAnswer .close();

}
int main()
{
outAnswer.open("text.txt", ofstream::in | ofstream::out | ofstream::app);


outAnswer.setf(ios::fixed, ios:: floatfield); // set up floating point capability
outAnswer.setf(ios::showpoint); // set up floating point capability
outAnswer << setprecision(2);	 // decimal up to two places
outAnswer.close();

BOX Bob (7.5, 2.75, 1.8, 0.1, 33.5, blue );	 //First box changing height
outAnswer << " For Box named Bob: " << endl;
Bob.print_report();
Bob.set_size(7.5,2.75, 0.75,0.1,33.5, blue);
Bob.print_report();

BOX John (45.0, 32.0, 6.33, 0.15, 530.0, red);	 //Second box changing length and thickness
outAnswer << " For Box named John: " << endl;
John.print_report();
John.set_size(11.0, 32.0, 6.33, 0.23, 530.0, green);
John.print_report();

BOX Dan (60.0, 30.0, 20.0, 0.80,400.0, black );
BETTERBOX Dan1( wood);	 // Third box 
outAnswer << " For Better Box named Dan: " << endl;
Dan.print_report();
Dan1.printreport();
Dan.set_size( 30.0, 15.5, 10.0, 0.40, 250.0, blue);
Dan1.setsize(wood);
Dan.print_report();
Dan1.printreport();



outAnswer << "Thanks and goodbye" << endl;



return 0;

}
Last edited on
one thing i dont understand i you are using both the classes seperatly the why are you inheriting the class . I is not need to inherent the class
I did't intend to use both classes separately but have betterbox inherit the values and functions from Box. I wasn't sure how to impliment changes to the values for Betterbox dan since they originated from box. When I compile it I still get some error about an unresolved external symbol even with your code bluecoder.
can you post the error you are getting .. Also changed the above code .. as
1
2
3
4
5
6
7
8
9
class BETTERBOX:BOX
	{
		public:
				BETTERBOX( int m ) : material ( m) {}
                                .........................................................     
                                .........................................................   
                                .........................................................

etc.                                .........................................................
Last edited on
The error code i was getting before was
error LNK2019: unresolved external symbol "public: __thiscall BETTERBOX::BETTERBOX(int)" (??0BETTERBOX@@QAE@H@Z) referenced in function _main
: fatal error LNK1120: 1 unresolved externals

Then with the above changes I got a different error
error C2512: 'BOX' : no appropriate default constructor available
which points to the latest change in the last post.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BETTERBOX:BOX
	{
		public:
				BETTERBOX( int m )  { material = m ; }
                                .........................................................     
                                .........................................................   
                                .........................................................

etc.                                .........................................................

class BOX	 //class definition
{
public:
        BOX() { } 	


I think this will solve your problem ..
I haven't tested it yet ..
Last edited on
Hello robdog4,

the error message from your original code is trying to tell you that you have not implemented a BETTERBOX constructor - ie something like:

1
2
3
4
BETTERBOX::BETTERBOX( int mat )
{
  // ... stuff
};


... and the compiler cannot find something appropriate from the base class BOX.

Now, I notice the (only) BOX constructor has a bunch of parameters associated with it (length, width, height etc)... does a BETTERBOX come as a fixed size only? if so, then you can use something along the lines of:

1
2
3
4
5
BETTERBOX::BETTERBOX( int mat )
  : material( mat ), BOX( 30.0, 15.5, 10.0, 0.40, 250.0, blue )
{
  // ... extra BETTERBOX stuff
};


If you immediately say "...but that makes no sense - I want my BETTERBOX to be of any/all sizes, and not just blue!" then perhaps this is highlighting an underlying problem with your class design so far.

The other alternative, as bluecoder mentions above, is to add the ability to construct a BOX with no parameters (this may or may not make sense to your mental image of what a BOX is). If a BOX is always a 'physical' thing (ie with non-zero dimensions), then perhaps the BETTERBOX constructor should receive a size as well as the material? In this case, you would then modify my second BETTERBOX() constructor above, and add the rest of the BOX parameters in (length, sizes, colour), which you can then pass down to your BOX constructor.

There are quite a few possibilities here to fix your problem, depending on what you would like a "BOX" and a "BETTERBOX" to do, and how they should differ.

One minor note - using an enum name as a data element ("material") is perhaps not the best idea... I got an interesting compile error when attempting to declare BETTERBOX(material _mat).
Last edited on
Thanks for the input bluecoder and mmay. Unfortunately, my deadline for this assignment already past; hopefully I get some points on it. I still get the error about the default constructor.

The book I was using did a crappy job explaining/showing inheitance so that may explain why my code doens't make sense but I based it on my instuctor's very siimple example of inheritance. The site's examples/explanations were a little obscure for me. My understanding was that inheritance would use the parameters from Box for Betterbox and build on it. I dont understand how to impliment consructors when using inheritance.
Could you guys clarify this? Can the parameters from Box be used by Betterbox this way?

My goal for Betterbox was simply to add another parameter (material) and two functions which that would tell the sum of dimenions and if it exeeded 65 from Box. My original Box program(I included in this post) worked fine. By the way mmay, the enum data type was a last minute addition to my original Box object, but since it worked with my original Box program I decided to use it again for Betterox.

Although I dont need to work on this assignment anymore, I still want to try to get this working and understand how to use inheritance... I hate unfinished work. Here's my original Box program to see what i was working from. Thanks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include<iostream>
#include<cmath>
#include<iomanip>
#include<string>
#include<fstream>
using namespace std;

ofstream outAnswer;

enum color{blue, red , green,black};			//color data type for box
class BOX								//class definition
{
public:
	
	BOX (double, double, double, double, double, int);		//contructor function
		~BOX();														//destructr function
		void set_size( double, double, double, double, double,int);		// changes l,w,h,th, wt,color
		double calc_area();											//for area
		double calc_volume();										//for volume
		void print_report();										// prints report of box

private:								// Member variables
	double length;
	double width;
	double height;
	double thickness;
	double weight;
	int color;
};

BOX::BOX (double l, double w, double h, double th, double wt, int c){		//constuctor
	length=l;
	width=w;
	height=h;
	thickness=th;
	weight=wt;
	color=c;
}

BOX::~BOX()														//destuctor
{
	outAnswer << " Destroying contents of BOX object" << endl;
}

void BOX::set_size (double l, double w, double h, double th, double wt, int c)	//Changes values for variables
{
	length=l;
	width=w;
	height=h;
	thickness=th;
	weight=wt;
	color=c;
	string colorname;
	
	switch (color){				// switch statement used to print out color of box
	case 0:
		colorname="blue";
		break;
	case 1:
		colorname="red";
		break;
	case 2:
		colorname="green";
		break;
	case 3:
		colorname="black";
	}
	outAnswer << "	 Size has been reset to " << length << " x " << width << " x " << height 
		<< endl << "	 Thickness = " << thickness << endl << "	 Weight = " << weight << endl << "	 Color: " 
		<< colorname << endl;
}

double BOX::calc_area()			//Calculates the area
{
	return (2*(length*width)+2*(height*length)+2*(height*width));
}

double BOX::calc_volume()		// Calculates the volume
{
	return (length*width*height);
}

void BOX::print_report()		// Prints out report of the box
{
	string colorname;
	switch (color){				// switch statement used to printout color of box
	case 0:
		colorname="blue";
		break;
	case 1:
		colorname="red";
		break;
	case 2:
		colorname="green";
		break;
	case 3:
		colorname="black";
	}

	outAnswer << "	 L x W x H = " << length << " x " << width << " x " << height << " , V = " << calc_volume() << endl << "	 Area = " <<
		calc_area() << endl << "	 Thickness = " << thickness << endl << "	 Weight = " << weight  <<  endl << "	 Color: "
		<< colorname << endl;
}

int main()
{
	outAnswer.open("Assignment5.txt");			//Outputs to text file
	

	outAnswer.setf(ios::fixed, ios:: floatfield);  // set up floating point capability
	outAnswer.setf(ios::showpoint);                // set up floating point capability
	outAnswer << setprecision(2);					// decimal up to two places

	BOX Bob (7.5, 2.75, 1.8, 0.1, 33.5, blue );						//First box changing height
		outAnswer << " For Box named Bob: " << endl;
		Bob.print_report();
		Bob.set_size(7.5,2.75, 0.75,0.1,33.5, blue);
		Bob.print_report();

	BOX John (45.0, 32.0, 6.33, 0.15, 530.0, red);					//Second box changing length and thickness
		outAnswer << " For Box named John: " << endl;
		John.print_report();
		John.set_size(11.0, 32.0, 6.33, 0.23, 530.0, green);
		John.print_report();
	
	BOX Dan (60.0 , 30.0, 20.0, 0.80,400.0, black);					// Third box with my own attributes and changes
		outAnswer << " For Box named Dan: " << endl;
		Dan.print_report();
		Dan.set_size( 30.0, 15.5, 10.0,  0.40, 250.0, blue);
		Dan.print_report();



		outAnswer << "Thanks and goodbye" << endl;
		
		
	
		return 0;

}
The code pasted above gives no error fro me .
also for constructor of the base class and the derived class .
In inheritance the base class constructor is called first and then the derived class consturctor is called . you can define

1
2
3
BETTERBOX( int m, double l, double w, double h, double th, double wt, int c):material( m ), BOX( l, w, h, th, wt, c )
	{
	}
@robdog4: hope your assignment got marked leniently >_<...

Okay, inheritance. Have you seen the phrase "IS-A" with regards to inheritance? This is the most important thing to remember.

When you base one class on another (we'll get to syntax in a moment), you are saying "this derived class IS A version of the base class (and can be used anywhere the base class can)." That last characteristic is the most important thing (theoretically speaking) - the derived class should be able to be used in place of the base class at any time. What this means, on a more practical level (and imho), is that derived classes can never get "smaller" (ie less functionality), they always must support all capabilities of the base class, and (usually) add some functionality. If you find you ARE wanting to remove functionality, then that's usually a sign your class design needs rethinking (ie your base class isn't really a 'base', and is doing too much).



Another small digression - have you met the concept of the "class initialiser list" yet? ie something that looks like this:

1
2
BOX::BOX (double l, double w, double h, double th, double wt, int c)
  : length(l), width(w), height(h), thickness(th), weight(wt), color(c) {};

What this does is allow you to list the data members of the class, and set initial values to them (usually based on constructor parameters, but the values can be constants, or expressions, or other function calls etc). The initialisation looks like a function call, except that the names used are data members. In this example it makes very little difference to the efficiency of the logic, however if BOX contained class members, then this "initialiser list" form saves the construction of a default value and an assignment operation (which may or may not be time-consuming). It's also been used above in bluecoder's and my examples.



Anyway, back to your derived class question... you have the right idea, just syntax is a little lacking. Once you've decided to add some extra information to the BOX class, you do it via your BETTERBOX derived class, but you have to be explicit on all the information you pass around - so, the BETTERBOX constructor needs to receive all the parameters for the base class, and pass them to it too. Something like the following would achieve what you have in mind:

1
2
BETTERBOX::BETTERBOX( int mat, double l, double w, double h, double th, double wt, int c )
  : material( mat ), BOX( l, w, h, th, wt, c ) { };

(note that base classes _have_ to be initialised in the 'initialisation list' - members are optional, but it is the ONLY way to get parameters directly to a base class constructor). Note also that in both these cases, once the members have been initialised (through the initialisation list after the single colon), there is nothing left to do in the constructor and hence the empty braces. If there is other stuff to do (eg printing out debug statements showing how it was initialised, or other calls to make), then that logic gets performed after the initialisation list has finished (including, in this case, the constructor for the base class). You can add some tracewrites into the constructors to see the order that these things get done, if you're curious.



Another detail when you derive classes - you have to specify the "protection" for the base class. What you have in your original declaration, is a "private" base class BOX, which means all the members of the base class BOX are NOT available via BETTERBOX objects. What you (usually) want is the BETTERBOX to be declared as:

1
2
3
4
5
class BETTERBOX : public BOX
{
  public:
    BETTERBOX(  int mat, double l, double w, double h, double th, double wt, int c );
...


(note the "public" before the BOX there). This will 'expose' the accessible methods of BOX to users of the BETTERBOX class. This is the means by which you "build on what has gone before", ie take all the functionality of a BOX, and add material support (or whatever). Note that the 'public' there does not override the protections present in the base BOX class - it only means that the public elements of BOX are available to users of BETTERBOX (and similarly, protected elements of BOX are available only to classes derived from BETTERBOX, etc).



You might be wondering, "Well, if my BETTERBOX : BOX {...} is equivalent to BETTERBOX : private BOX { ... }, why would anyone ever want to use it?" the answer to that is "fairly rarely" (in my experience). You would 'hide' the base class like that if you wanted your derived class to have total control over how information gets to the base class - ie, you would need to implement the entire interface to BOX as well as the new BETTERBOX methods. This might be useful if you felt the BOX interface was going to change, or if BOX was being written by someone else and you didn't want your code that used BETTERBOX to be dependent on the whims of that person... there are probably other examples of when you might want to "hide" an interface, but I can't think of any right now.



Sorry for the wordiness - but I hope this helps give you some idea (and some keywords to google for) about how to use inheritance <(^_^). If things don't seem to be making sense, feel free to question further.
Last edited on
Topic archived. No new replies allowed.