I understand this isn't the best title but I'm not sure how to explain this problem that I'm having without examples.
I have a base class (called vector3)
class vector3 {
protected:
double x,y,z;
public:
vector3(): x(0),y(0),z(0) {}
vector3(double xin, double yin, double zin): x(xin),y(yin),z(zin) {}
~vector3() {}
//...other stuff
};
Then I have another class, derived from vector3, called vector4:
class vector4 : public vector3 {
protected:
double ct;
public:
vector4(): vector3(0,0,0), ct=0 {}
vector4(double ctin): ct(ctin) {}
vector4(double ctin, double xin, double yin, double zin):
vector3(xin, yin, zin), ct(ctin) {}
vector4(double ctin, vector3 v):
vector3(v.getx(), v.gety(), v.getz()), ct(ctin) {}
~vector4() {}
//...more other stuff
};
And that's all fine, but now I've got a class called particle defined like this:
class particle : public vector4 {
protected:
//vector4 r;
double mass;
//vector3 beta;
public:
particle(): vector4(0,0,0,0), mass=0, vector3(0,0,0) {}
particle(vector4 rin, double massin, vector3 betain):
vector4(rin.getx(),rin.gety(),rin.getz(),rin.getct()),
mass=0,
vector3(betain.getx(),betain.gety(),betain.getz()) {}
~particle() {}
//...Further stuff
};
So now the question is:
How do I return the x value, y value and z value of the particle's position, and the x value, y value and z value of the particle's beta vector inside a function in the particle class?
With vector 4 I'd just do:
double getx() const {
return x;
}
double gety() const {
return y;
}
etc, but what would I use in the particle's class?
Position and beta vector are attributes of a particle, so you should be using aggregation instead of inheritance:
class particle {
protected:
vector4 r;
double mass;
vector3 beta;
// ...
You should only use inheritance where there is an is-a relationship between the subclass and superclass.
In your case, particle is a vector4, so you can define your getters public in vector4, and directly call particle.getX()
However, this does not seem to be a good idea, in my opinion, particle should contain a vector since it is not a specialisation of the vector4 class.
so let's say particle has a vector called _vector
you can define a method like this :
double getX(void) const
{
return (_vector.getX());
}
Same goes for getY
Related
Suppose I have a simple class that defines a Circle object:
class Circle {
public:
Circle(const double x): radius(x) { ; }
const double getRadius() const { return radius; }
private:
const double radius;
};
This seems like a common convention and subscribes to the OO principle of data-hiding. My question is why do this? Would it not be simpler to make radius a public member? For a mutable member, this would obviously be a bad idea, since anyone could modify the circle's radius, but since it's const, I see no need to make it private. Would it be acceptable to do something like this?:
class Circle {
public:
Circle(const double x): radius(x) { ; }
const double radius;
};
I have a base class MovingObject defined like this:
class MovingObject
{
protected:
double x;
double y;
double speed;
double damage;
double distance(double x1, double y1, double x2, double y2)
{
return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}
public:
MovingObject(double x, double y, double speed, double damage);
virtual bool isCollide(MovingObject* Object);
virtual void draw() {};
virtual void move() {};
};
And I have 2 inherited classes from MovingObject class, Zombie and Bullet :
class Bullet : public MovingObject
{
private:
double dirX;
double dirY;
public:
Bullet(double x, double y, double speed, double damage, double dirX, double dirY);
bool isCollide(Zombie* pZombie);
void draw();
void move();
};
class Zombie : public MovingObject
{
private:
double hpMax;
double hpCurrent;
double attackCD;
double attackRate;
public:
Zombie(double x, double y, double speed, double damage, double hpMax, double hpCurrent, double attackCD, double attackRate);
bool isCollide(Bullet* pBullet);
void draw();
void move();
void getHit();
void drawHPBar();
void decreaseAttackCD();
void refreshAttackCD();
};
For example, lets say I want to check collision between Bullet and Zombie objects in the game. I want to check this collision in Bullet class like follows:
bool Bullet::isCollide(Zombie* pZombie) {
if (distance(x, y, pZombie->x, pZombie->y) < 10) {
pZombie->getHit();
return true;
}
else
return false;
}
But when I try to access the x and y attributes of Zombie in Bullet class, I can't access it. What I want to ask is, is it possible to check collision like this without using getX() and getY() functions ? I believe there is a flaw in my thinking because I am fairly new to C++ and OOP concepts. I do not want to full answer from you, I just want someone to point right path for me. Thank you in advanced.
Bullet cannot access Zobmbies protected members because it is not derived from Zombie. If you only need read access to x and y, you need constant getters in the MovingObject class.
class MovingObject
{
public:
double GetX() const { return x; }
double GetY() const { return y; }
protected:
...
};
and then use them in Bullet::isCollide()
if (distance(x, y, pZombie->GetX(), pZombie->GetY()) < 10) {
pZombie->getHit();
return true;
}
Please avoid using friend. With growing number of subclasses you will have to make them all friends.
I have this HW question that I have been stuck for hours on that I can't seem to make sense of. It's kind of hard to put to words my actual question but I will try my best. How can I make my outside-member function find the distance between a circle using a class which references another class? In my code below:
//Header
class Point
{
public:
Point();
Point(int, int);
Point(const Point& object);
int getX() const;
int getY() const;
void setX(int);
void setY(int);
double calculate_area();
void print() const;
private:
int x;
int y;
};
class Shape
{
public:
Shape();
double calculate_area();
void print() const;
protected:
double area;
};
class Circle : public Shape
{
public:
Circle();
Circle(const Point&, double);
double getRadius() const;
void setRadius(double);
void calculate_area();
void print() const;
private:
double radius;
Point center;
};
class RTriangle : public Shape
{
public:
RTriangle();
RTriangle(double, double);
double hyp();
void calculate_area();
void print() const;
private:
double side1;
double side2;
};
inline double distance(Circle& other)
{
return sqrt(pow(other.center.x, 2) + pow(other.center.y, 2));
}
#endif
//Implementation.cpp of what i think is important for you guys to see
Point::Point(int inX, int inY) // normal constructor
{
x = inX;
y = inY;
}
Point::Point(const Point &object) // copy constructor needed to use for center of circle
{
x = object.x;
y = object.y;
}
Circle::Circle(const Point& object, double inRad) // center is x & y... radius for circle
{
center = object;
radius = inRad;
}
My outside member function (inline double distance) isn't working. This is the first time I have tried doing this so I apologize if I do not word it well. I am essentially trying to use only the Circle class which inherits point center and point center is defined in the first class as x and y. Is it possible to do such a thing (specifically use x and y which is inside Point center)? I don't know if it's possible to access x and y through center.
Given a Point, functions not in Point can access its x and y members with the public getX() and getY() methods in your example.
However, Circle's center member is not public and has no public accessors. The most straightforward fix would add a public method
Point getCenter(); // or Point const &getCenter() if you like)
to Circle.
Here is my task:
Design classes Circle and Square which are inherited from class Shape (which contains center of gravity which is common characteristic for all shapes, function for moving center of gravity for specific value and virtual functions circumference, area and read). Classes should have specific functions for calculating circumference and area, as well as for reading data members.
Here is what I have done:
#include <iostream>
using namespace std;
class Point {
private:
float x;
float y;
public:
Point();
Point(float,float);
~Point();
};
Point::Point() {
}
Point::Point(float a,float b) {
x=a;
y=b;
}
Point::~Point() {
}
class Shape {
public:
Shape(void);
Shape(Point);
virtual float circumference(void) {}
virtual float area(void) {}
protected:
Point center_of_gravity;
};
Shape::Shape(void) {
}
Shape::Shape(Point a) {
center_of_gravity=a;
}
//----------------------------------------
class Circle:public Shape {
private:
float radius;
public:
float x;
float y;
Circle();
Circle(float);
virtual float circumference(void);
virtual float area(void);
};
Circle::Circle(void) {
}
Circle::Circle(float a) {
radius=a;
}
float Circle::area(void) {
float area_of_circle;
const float pi=3.14159;
area_of_circle=radius*radius*pi;
return area_of_circle;
}
float Circle::circumference(void) {
float circumference_of_circle;
const float pi=3.14159;
circumference_of_circle=2*radius*pi;
return circumference_of_circle;
}
//----------------------------------------
class Square:public Shape {
private:
float length;
public:
Square();
Square(float);
virtual float circumference(void);
virtual float area(void);
};
Square::Square(void) {
}
Square::Square(float a) {
length=a;
}
float Square::area(void) {
float area_of_circle;
area_of_circle=length*length;
return area_of_circle;
}
float Square::circumference(void) {
float circumference_of_square;
circumference_of_square=4*length;
return circumference_of_square;
}
int main() {
float a,b;
cout<<"Enter coordinates of center of gravity: "<<endl;
cin>>a>>b;
Point center_of_grav(a,b);
cout<<"Enter length of square: "<<endl;
cin>>a;
Square square(a);
cout<<"Enter radius of circle: "<<endl;
cin>>a;
Circle circle(a);
Shape *shape1=&circle;
Shape *shape2=□
cout<<"Area of circle is "<<shape1->area()<<", circumference is "<<shape1->circumference()<<endl;
cout<<"Area of square is "<<shape2->area()<<", circumference is "<<shape2->circumference()<<endl;
}
Is it ok? How can I realize function for moving center of gravity?
How can I read center of gravity for Circle and Square (it is inherited from class Shape)? They mean it (I think) when they say "...as well as for reading data members."
EDIT:
After I put all suggestion I got in one place:
#include <iostream>
using namespace std;
class Point{
private:
float x;
float y;
public:
Point();
Point(float,float);
~Point();
friend class Shape;
};
Point::Point(){
}
Point::Point(float a,float b){
x=a;
y=b;
}
Point::~Point(){
}
//----------------------------------------
class Shape{
public:
Shape(void);
Shape(Point);
virtual float area(void)=0;
virtual float circumference(void)=0;
protected:
float x_coordinate;
float y_coordinate;
Point center_of_gravity;
};
Shape::Shape(void){
}
Shape::Shape(Point a){
center_of_gravity=a;
x_coordinate=a.x;
y_coordinate=a.y;
}
//----------------------------------------
class Circle:public Shape{
private:
float radius;
public:
Circle();
Circle(Point,float);
virtual float area(void);
virtual float circumference(void);
};
Circle::Circle(void){
radius=0;
}
Circle::Circle(Point p,float a) : Shape(p), radius(a){
}
float Circle::area(void){
float area_of_circle;
const float pi=3.14159;
area_of_circle=radius*radius*pi;
return area_of_circle;
}
float Circle::circumference(void){
float circumference_of_circle;
const float pi=3.14159;
circumference_of_circle=2*radius*pi;
return circumference_of_circle;
}
//----------------------------------------
class Square:public Shape{
private:
float length;
public:
Square();
Square(Point,float);
virtual float area(void);
virtual float circumference(void);
};
Square::Square(void){
length=0;
}
Square::Square(Point p,float a) : Shape(p), length(a){
}
float Square::area(void){
float area_of_circle;
area_of_circle=length*length;
return area_of_circle;
}
float Square::circumference(void){
float circumference_of_square;
circumference_of_square=4*length;
return circumference_of_square;
}
//----------------------------------------
int main(){
float a,b;
cout<<"Enter coordinates of center of gravity: "<<endl;
cin>>a>>b;
Point center_of_grav(a,b);
cout<<"Enter length of square: "<<endl;
cin>>a;
Square square(center_of_grav,a);
cout<<"Enter radius of circle: "<<endl;
cin>>a;
Circle circle(center_of_grav,a);
Shape *shape1=&circle;
Shape *shape2=□
cout<<"Area of circle is "<<shape1->area()<<", circumference is "<<shape1->circumference()<<endl;
cout<<"Area of square is "<<shape2->area()<<", circumference is "<<shape2->circumference()<<endl;
}
1.Constructor design
How will you set their gravity center ?
Point center_of_grav(a,b);
...
Square square(c); // what's the gravity center ?
You have to design the constructor of the derived, so that it has all information required to construct the base:
Square square(center_of_grav, c);
To achieve this, you have to define it in the following way (of course adapt the class definition accordingly):
Square::Square(Point p, float a) : Shape(p), lentgh(a) {
// ... reserve this for more complex initisalisations
}
Note that your default constructor leave the objects uninitialized.
2.Design of Shape
Very important: Shape is a polymorphic class with virtual functions. You shall take the habit to define a virtual destructor in this case.
Minor remark: It makes no sense to create directely a Shape object. It's an abstract concept. There is no default rule to calculate an area or a circumference that could apply to most of the shape. Therefore, I'd strongly suggest to define these two functions as pure virtual:
class Shape {
...
virtual float circumference(void) =0; // pure virtual
virtual float area(void) = 0;
...
};
Advantage: as soon as you have a pure virtual function in a class, this class becomes abstract, and you won't be able to instantiate an object of that class by error. The compiler will make sure that you instatiate only concrete derivates of the abstract concept.
3.Make sure your code complies with requirements
Well it's a detail and you certainly have taken care of it, but:
Classes should have specific functions for calculating circumference
and area, as well as for reading data members.
So I think you should foresee some getters to access to the protected data:
Example:
class Shape {
...
Point get_gravity_center();
...
};
Point Shape::get_gravity_center() {
return center_of_gravity;
}
I let you complete the others. Simply imagine that you have to print in main() the description of a circle (coordinates of the center and radius), and you'll see the getters that are missing.
Edit following your question:
As you we've defined the getter for the center of gravity at the shape level, you don't need to define it again in the derivates. You could then simply call it in main(). The problem is that you also need to access to the coordinats of that point. So:
class Point {
...
float get_x() { return x; }
float get_y() { return y; }
...
};
With this you can write in main():
cout << "Circle of center ("<<circle.get_gravity_center().get_x()<<","
<< circle.get_gravity_center().get_y()<<")"<<endl;
P.S: with the center_of_gravity as member of shape, you no longer need to duplicate the coordinates otf that point.
To answer your question, it is not OK. Your code does show some pretty clear thinking, so that's good. It just needs to be finished. All data members of all classes must be given values when objects are constructed. Otherwise, they get random values, and that is never good practice. So init the CG in the Shape constructor.
Also, remove x and y from circle, if you mean them to represent CG -- that info is inherited already.
Finally, to realize a function for moving CG, I'd recommend adding a setter method to the Shape class, where it can be inherited by those other two classes. With that, you should be good to go.
I'm wondering what is the recommended way to avoid the issue below.
I have a class rigidBody3D that has a pointer to another rigidBody structure, and a class box3D that inherits rigidBody3D.
class rigidBody3D {
public:
void setPosition(float x, float y, float z);
rigidBody* rb;
};
class box3D : public rigidBody3D {
public:
box3D(float w float h, float l);
..other box functions..
};
I then have 2D classes that use these 3D classes.
class rigidBody2D {
public:
rigidBody2D();
void setPosition(float x, float y);
rigidBody3D body;
};
class box2D : public rigidBody2D {
public:
box2D(float w, float h);
box3D box;
};
For example rigidBody2D's setPosition calls the 3D setPosition of its rigidBody3D.
void rigidBody2D::setPosition(float x, float y)
{
body.setPosition(x,y,0);
}
THE ISSUE:
As is, creating a box2D object creates two rigidBody pointers. One because box2D inherits rigidBody2D which has a rigidBody3D. The other because box2D has a box3D object that inherits rigidBody3D.
I only want one rigidBody pointer. I also want to be able to call the 2D setPosition for 2D classes like box2D, but also call their 3D specific functions, like box2D calling box3D.
SOLUTION:
I used virtual inheritance to solve the problem, and also inherited the 3D classes instead of having objects of them.
class rigidBody3D {
public:
void setPosition(float x, float y, float z);
rigidBody* rb;
};
class box3D : public virtual rigidBody3D {
public:
box3D(float w float h, float l);
..other box functions..
};
class rigidBody2D : private virtual rigidBody3D {
public:
rigidBody2D();
void setPosition(float x, float y);
};
class box2D : public rigidBody2D, private box3D {
public:
box2D(float w, float h);
};
void rigidBody2D::setPosition(float x, float y)
{
rigidBody3D::setPosition(x,y,0);
}
Your comment:
I want (...) 2D objects, which are 3D objects that are drawn in 2D and have their z
components set to 0
strongly suggest that a rigidBody2D is a rigidBody3D, and that a box2D is a box3D. Hence it would seem natural to prefer inheritance over compostion:
Alternative 1: simple inheritance
Here we'll consider that the root of all these 2D and 3D objects is the rigidBody2D.
One question remains: is a box2D more a kind of box3D or more a rididBody2D ?
class rigidBody2D : public rigidBody3D {
public:
rigidBody2D();
void setPosition(float x, float y);
// no body anymore: it's inherited from rigidBody3D
};
class box2D : public box3D { // is it more like a box3d or more like a rigiBbody2D ? You decide !
public:
box2D(float w, float h);
// no box anymore: it's inherited from box3D
};
box2D::box2D (float w, float h) : box3D (w, h, 0) { /*...*/ } // how to create a box2D as a special case of box3D
void rigidBody2D::setPosition(float x, float y) // call the setpos of the parent.
{
rigidBody3D::setPosition(x, y, 0); // call parent's setpos
}
All therse objects inherit from rigidBody3D and have then a pointer to a rigidBody.
A further question is in fact to know whether a rigidBody3D should not himself inherit from a rigidBody, or if there are strong arguments against (for ex: if the lifespan of the two are different).
Alternative 2: multiple inheritance
Here it's about the design of box2D. Is it more a box3D, having the same kind of member functions but than a box3D, but taking into account that third dimension is 0 ? Or is it more a rigidBody2D, because it should have and use all the member functions provided by this object ?
If you can easily decide, go back to alternative 1.
If you can't decide, because it's a little bit both, then you could consider multiple inheritance:
class box2D : public box3D, public rigidBody2D {
public:
box2D(float w, float h);
// no box anymore: it's inherited from box3D
};
THen you would inherit member (function and data of both). Hower multiple inheritance ain't easy. You'd have here 2 rigidBody pointers: those who are inherited from the box, and those who are inherited from the body.
This issue could be solved in your case by making inheritance of rigidBody3D virtual:
class rigidBody2D : public virtual rigidBody3D { ... };
class box3D : public virtual rigidBody3D { ... };
in this case, if an object inherits several time rigidBody3D, only one of such subobject is created.
it seems to me that 2d and 3d objects are related only by the fact that they are implemented in terms of a rigidbody*. The semantics of setPosition are different for the two concepts.
Another way to say this is that a 2d body is not a kind-of 3d body, it's a different concept so it seems that there should be no inheritance relationship between them.
so I would start by thinking along these lines:
struct rigid_body_3d_concept {
virtual ~rigid_body_3d_concept();
void set_position(double x, double y, double z) {
_impl->really_set_the_position(x, y, z);
}
private:
rigidbody* _impl;
};
struct rigid_body_2d_concept {
virtual ~rigid_body_2d_concept();
void set_position(double x, double y) {
_impl->really_set_the_position(x, y, 0);
}
private:
rigidbody* _impl;
};
struct box3d
: public rigid_body_3d_concept
{
box3d(double w, double h, double l);
};
struct box2d
: public rigid_body_2d_concept
{
box2d(double w, double h);
};