# Thread: Relating classes using composition

1. ## Relating classes using composition

Originally I created an inheritance for these two classes. I had everything working except one function in circleType, and last night laserlight helped debug that. Well, today I realize that this is a composition relationship not inheritance. So, I reworked all the code to reflect the new relation. And, again tonight I have one function that doesn't seem to be working right.

The problem is in the circle function calls at the end of main. Everything works through the calc and print of the area and circum. But, the first cindyCircle.printPoint() function prints (0, 0) when it should print (3, 3). I thought this problem was in the cindyCircle.setPointRadius() function. But, the functions following it worked, so then I narrowed it down the the cindyCircle.printPoint() but I still can't get it to work. THe second cindyCircle.printPoint() works fine after I explicitly setX and setY.

Can anyone see what I am not?
Thanks!

pointClass.h
Code:
```#ifndef H_POINT
#define H_POINT

#include <iostream>
using namespace std;

class pointType
{
public:
pointType();
//default constructor
pointType(int xCoord, int yCoord);
//constructor

void setPoint(int xCoord, int yCoord);
//stores the values of xCoord into x, and yCoord into y
void setX(int xCoord);
//stores the value of xCoord into x and y remains unchanged
void setY(int yCoord);
//x remains unchanged and stores the value of yCoord into y
void getPoint(int & xCoord, int & yCoord);
//returns the value of x into xCoord and y into yCoord
void getX(int & xCoord);
//returns just the value of x into xCoord
void getY(int & xCoord);
//returns just the value of y into yCoord
void printPoint() const;
//prints (x, y)
void printX()const;
//prints just x
void printY()const;
//prints just y

private:
int x;
int y;
};

#endif```
pointClass.cpp
Code:
```#include "pointClass.h"

pointType::pointType()
{
setPoint(0, 0);
}

pointType::pointType(int xCoord, int yCoord)
{
setPoint(xCoord, yCoord);
}

void pointType::setPoint(int xCoord, int yCoord)
{
x = xCoord;
y = yCoord;
}

void pointType::setX(int xCoord)
{
x = xCoord;
}

void pointType::setY(int yCoord)
{
y = yCoord;
}

void pointType::getPoint(int & xCoord, int & yCoord)
{
xCoord = x;
yCoord = y;
}

void pointType::getX(int & xCoord)
{
xCoord = x;
}

void pointType::getY(int & yCoord)
{
yCoord = y;
}

void pointType::printPoint() const
{
cout << "(" << x << ", " << y << ")" << endl;
}

void pointType::printX() const
{
cout << "The value of x is: " << x << endl;
}

void pointType::printY() const
{
cout << "The value of y is: " << y << endl;
}```
circleClass.h
Code:
```#ifndef H_CIRCLE
#define H_CIRCLE

#include <iostream>
#include <string>
#include <cmath>
#include "pointClass.h"

const double PI = 3.14159;

class circleType: public pointType
{
public:
circleType();
circleType(int xCoord, int yCoord, int radius);

double calcArea();
double calcCircum();
void WhereAmI();

void printArea();
void printCircum();

private:
pointType x, y, point;
int r;
};

#endif```
circleClass.cpp
Code:
```#include "pointClass.h"
#include "circleClass.h"

circleType::circleType()
:x(), y()
{
r = 0;
}

circleType::circleType(int xCoord, int yCoord, int radius)
: x(x), y(y)
{
}

{
}

{
x.setX(xCoord);
y.setY(yCoord);
point.setPoint(xCoord, yCoord);
}

{
}

{
point.getX(xCoord);
point.getY(yCoord);
}

double circleType::calcArea()
{
return (PI * pow(r, 2));
}

double circleType::calcCircum()
{
return (2 * PI * r);
}

{
cout << "The current value of radius is: " << r << endl;
}

void circleType::printArea()
{
cout << "The area of a circle with a radius of "
<< r << " is " << calcArea() << endl;
}

void circleType::printCircum()
{
cout << "The circumference of a circle with a radius of "
<< r << " is " << calcCircum() << endl;
}

{
point.printPoint();
x.printX();
y.printY();
cout << " and the radius of the circle is " << r << "." << endl;
}

void circleType::WhereAmI()
{
int xCoord,
yCoord;
point.getPoint(xCoord, yCoord);
x.getX(xCoord);
y.getY(yCoord);
if (xCoord > 0 && yCoord > 0)
cout<< "My Center is in the first quadrant of the cartesian plane." << endl;
else if (xCoord > 0 && yCoord < 0)
cout << "My Center is in the second quadrant of the cartesian plane." << endl;
else if (xCoord < 0 && yCoord < 0)
cout << "My Center is in the third quadrant of the cartesian plane." << endl;
else
cout << "My Center is in the fourth quadrant of the cartesian plane." << endl;
}```
main.cpp
Code:
```#include "pointClass.h"
#include "circleClass.h"

//to test the pointClass prior to building the circleClass
int main()
{
int mainX = 0,
mainY = 0,
returnValue = 0;

//operation calls to check the point class
pointType cindyPoint;

cout << "The x and y values of cindyPoint are: ";
cindyPoint.printPoint();
cindyPoint.setX(19);
cindyPoint.setY(57);
cout << "The new x and y values of cindyPoint are: ";
cindyPoint.printPoint();
cout << "Before the get functions, mainX = " << mainX << ", mainY = " << mainY
<< ", \n\tand returnValue (mainX + mainY) = " << returnValue << "." << endl;
cindyPoint.getX(mainX);
cindyPoint.getY(mainY);
returnValue = mainX + mainY;
cout << "After the get functions, mainX = " << mainX << ", mainY = " << mainY
<< ", \n\tand returnValue (mainX + mainY) = " << returnValue << "." << endl;

cout << "The x and y values of badPoint are: ";
cout << "The x and y values of badPoint are now: ";
cout << "The x and y values of badPoint have been reset to: ";

//operation calls to check the circle class
circleType cindyCircle;

cout << "\ncindyCircle has default x and y values of: ";
cout << "cindyCircle has reset values to: ";
cindyCircle.calcArea();
cindyCircle.printArea();
cindyCircle.calcCircum();
cindyCircle.printCircum();
cout << "The x and y values of cindyPoint now are: ";
cindyCircle.printPoint();
cindyCircle.WhereAmI();
cindyCircle.setX(-3);
cindyCircle.setY(-3);
cout << "The x and y values of cindyPoint now are: ";
cindyCircle.printPoint();
cindyCircle.WhereAmI();
}```

2. Code:
```circleType::circleType(int xCoord, int yCoord, int radius)
: x(x), y(y)```
This code isn't right. You're using x and y to initialize themselves and ignoring xCoord and yCoord.

Your circleType class has a pointType x and pointType y. Shouldn't you just have a single pointType for x and y? In fact, shouldyou just have pointType center or something that holds the single point that is the center of the circle? Your constructor can still take an xCoord and yCoord, you would then just pass both to the constructor of your center variable.

BTW, I definitely agree that you want composition, not inheritance here.

3. If I have just a single pointType for both x & y, then if I want to initialize them separately is there a problem?

4. I modified my circleType class and added a few more functions which seems to have corrected the problem I just don't know if what I did is "correct." I will repost the circleType .h and .cpp for review by you all.

Feel free to hack away. I am just feeling myself through all this. My instructor is absent in all of this and when he does respond I wonder... This is his last:
"A large part of programming, as you are finding out, is “rolling up your shirt sleeve” and trying a solution or “if you don’t succeed…”. Also you will find that there is more than one way."
Well Duh!

NEW circleType.h
Code:
```#ifndef H_CIRCLE
#define H_CIRCLE

#include <iostream>
#include <string>
#include <cmath>
#include "pointClass.h"

const double PI = 3.14159;

class circleType: public pointType
{
public:
circleType();
circleType(int xCoord, int yCoord, int radius);

void setX(int xCoord);
void setY(int yCoord);
void setPoint(int xCoord, int yCoord);

double calcArea();
double calcCircum();
void WhereAmI();

void printPoint() const;
void printArea();
void printCircum();

private:
pointType x, y, point;
int r;
};

#endif```
NEW circleType.cpp
Code:
```#include "pointClass.h"
#include "circleClass.h"

circleType::circleType()
:x(), y()
{
r = 0;
}

circleType::circleType(int xCoord, int yCoord, int radius)
: x(x), y(y)
{
}

void circleType::setPoint(int xCoord, int yCoord)
{
point.setPoint(xCoord, yCoord);
}

void circleType::setX(int xCoord)
{
point.setX(xCoord);
}

void circleType::setY(int yCoord)
{
point.setY(yCoord);
}

{
}

{
x.setX(xCoord);
y.setY(yCoord);
point.setPoint(xCoord, yCoord);
}

{
}

{
point.getX(xCoord);
point.getY(yCoord);
}

double circleType::calcArea()
{
return (PI * pow(r, 2));
}

double circleType::calcCircum()
{
return (2 * PI * r);
}

{
cout << "The current value of radius is: " << r << endl;
}

void circleType::printArea()
{
cout << "The area of a circle with a radius of "
<< r << " is " << calcArea() << endl;
}

void circleType::printCircum()
{
cout << "The circumference of a circle with a radius of "
<< r << " is " << calcCircum() << endl;
}

void circleType::printPoint() const
{
point.printPoint();
}

{
point.printPoint();
cout << " and the radius of the circle is " << r << "." << endl;
}

void circleType::WhereAmI()
{
int xCoord,
yCoord;
point.getPoint(xCoord, yCoord);
x.getX(xCoord);
y.getY(yCoord);
if (xCoord > 0 && yCoord > 0)
cout<< "My Center is in the first quadrant of the cartesian plane." << endl;
else if (xCoord > 0 && yCoord < 0)
cout << "My Center is in the second quadrant of the cartesian plane." << endl;
else if (xCoord < 0 && yCoord < 0)
cout << "My Center is in the third quadrant of the cartesian plane." << endl;
else
cout << "My Center is in the fourth quadrant of the cartesian plane." << endl;
}```

5. So, if I have point.getPoint() I can also have point.getX() and point.getY() ?
And would that would eliminate some of the redundancy I feel I have in my definitions.? To use point.getX and Y or point.setX and Y etc...

6. I think I figured it out. I took your advice Daved and changed :x(x), y(y). It wasn't working when I included defined values in the initialization of my circleType.

Code:
```circleType::circleType(int xCoord, int yCoord, int radius)
: x(x), y(y)```
now looks like:
Code:
```circleType::circleType(int xCoord, int yCoord, int radius)
:point(xCoord, yCoord)```
Now the define value constructor uses the correct values instead of initializing the point to (0, 0) and the radius to the defined value.

Thanks, I think I may have it worked out, but I will check back to see if anyone else has found more errors that I haven't uncovered yet.
Thanks!

7. It just makes more sense that way, right? You have to understand what the things represent. Your circle's data consists of a center point and a radius, right? So you only need one member variable point and one member variable for the radius.

You also have to think of pointType as a type. Forget the x and y parts of it, if you want a point, use a pointType.

8. I am trying to understand!

That part, I thought, was working until you pointed out the problem. So I added values to the declaration and it didn't work! So...I fixed it the way you suggested.

I write everything out and think things through, or so I think, before ever typing a word. Then when things don't work, I start changing what I think the problem is, and sometimes, I get so deep, that I have to step away and backtrack a ways. I have started coping the code I am going to change into word before I change it. That way, if what I think will work doesn't, I can go back to what I had and rethink yet again.

It hasn't been too difficult so far, once I understand what the book is "trying" to explain. Sometimes, that isn't done too well.

My next assignment is to create a cylinder class using all of the above. I will definately use composition from the beginning. There is nothing worse than doing an assignment twice. I sure did learn a bit more than I expected about both inheritance and composition.

9. I'm not saying you are a bad programmer for not understanding, I'm saying that when you understand what different things mean before you code it makes the coding easier. Everything you describe about making changes until you get so deep that it is all confusing is normal for pretty much all programmers. Just keep working and do your best to "step back" for every decision you make.

10. Thanks, but I am not a programmer, I am a student of programming at this point.
I aspire to be a programmer, but time will tell if I have what it takes, and what language suits me. I may just have to stay in finance.

11. Well, surely even in Finance programming, you will sooner or later have to work on something you are not familiar with. What if your financial software requires that you draw a bunch of symbols in a graph - wouldn't a basic understanding of classes and inhearitance be really helpful?

It is always difficult when you start out with a new project, or a new area that you are not familiar with. It's part of the challenge in programming - and it can be hard at times, but the feeling when you get it working is great.

--
Mats

12. Code:
```class circleType: public pointType
{
public:
circleType();
circleType(int xCoord, int yCoord, int radius);

void setX(int xCoord);
void setY(int yCoord);
void setPoint(int xCoord, int yCoord);

double calcArea();
double calcCircum();
void WhereAmI();

void printPoint() const;
void printArea();
void printCircum();

private:
pointType x, y, point;
int r;
};```
Are you still deriving from pointType? What about the const-ness of those other functions?

13. All the versions of code posted so far use both composition AND inheritance.
In fact in that code, there are four instances of pointType, in every circleType instance.
Including the 'r' that's 4x2+1 = 9 intetgers, or 36 bytes for every circle.

Don't derive from pointType, and only declare one pointType member.
This will bring the class size down do 1x2+1 = 3 integers, or 12 bytes for every circle.