Situation:
Bullet inherits from GameObject.
GameObject has method 'GetCoords' and 'SetCoords'
Bullet has method 'MoveObject'
'MoveObject' gets the coords from 'GetCoords' to set them in 'SetCoords'
Coordinates do not change
GameObject.h
struct Coordinates {
float xPos;
float yPos;
};
//GameObject
class GameObject {
public:
GameObject() {};
GameObject(unsigned int a_id, float a_xPos, float a_yPos, float a_speed, States a_state = State::Idle);
~GameObject();
//Methods
void MoveObject(float changeXPos, float changeYPos);
void MoveObject(float changeYPos);
Coordinates GetCoords() { return Coords; }
void SetCoords(Coordinates a_Coords) { Coords = a_Coords; }
private:
Coordinates Coords;
};
Bullet.h
#pragma once
#include "GameObject.h"
class Bullet : public GameObject {
public:
Bullet(unsigned int a_Id, float a_xPos, float a_yPos, float a_speed, States a_state = State::Idle) : GameObject(a_Id, a_xPos, a_yPos, a_speed, a_state) {}
void MoveObject(float changeYPos);
};
Bullet.cpp
#include "Bullet.h"
void Bullet::MoveObject(float changeYPos)
{
Coordinates coords = GameObject::GetCoords();
coords.yPos += changeYPos;
this->SetCoords(coords);
}
I tried 'this->SetCoords();' and 'GameObject::GetCoords();' to no avail.
I just tried this:
void GameObject::MoveObject(float changeYPos)
{
Coordinates coords = GetCoords();
coords.yPos += changeYPos;
SetCoords(coords);
}
Main Game Class
The point where MoveObject is getting called:
for each (auto bullet in bullets)
{
Coordinates coords = bullet.GetCoords();
std::cout << bullet.GetCoords().xPos << ", " << bullet.GetCoords().yPos << std::endl;
bullet.MoveObject(.3f);
if (bullet.GetCoords().yPos > m_iScreenHeight) {
bullets.erase(bullets.begin());
DestroySprite(bullet.GetId());
break;
}
coords = bullet.GetCoords();
std::cout << bullet.GetCoords().xPos << ", " << bullet.GetCoords().yPos << std::endl;
MoveSprite(bullet.GetId(), bullet.GetCoords().xPos, bullet.GetCoords().yPos);
CheckHitEnemy(bullet.GetCoords().xPos, bullet.GetCoords().yPos, bullet.GetId());
}
The second cout does have different coordinates.
The point where the bullets get created, this gets called when the spacebar is pressed:
Bullet bullet(CreateSprite("./images/bullet.jpg", 3, 20, true), xPos, yPos, 1);
MoveSprite(bullet.GetId(), bullet.GetCoords().xPos, bullet.GetCoords().yPos);
bullets.push_back(bullet);
It seems to me like you are missing the virtual keyword before your MoveObject declaration in the base class.
The way this is now, when you have a GameObjectpointer/reference it will call MoveObject from GameObject and not from Bullet
So maybe change it to
virtual void MoveObject(float changeXPos, float changeYPos);
etc.
I am not sure if it fixes you problem, but later you can run into other problems with that. If you have c++11 available you should also look into the override keyword
Related
I got a virtual method problem when trying code from https://en.wikipedia.org/wiki/Bridge_pattern.
Error messages are:
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
The code was compiled with g++ -o bridge bridge.cpp -std=c++11
Why drawing_api_.DrawCircle() called the virtual function in DrawingAPI?
#include <iostream>
#include <string>
#include <vector>
class DrawingAPI {
public:
virtual ~DrawingAPI() = default;
virtual std::string DrawCircle(float x, float y, float radius) const = 0;
};
class DrawingAPI01 : public DrawingAPI {
public:
std::string DrawCircle(float x, float y, float radius) const override {
return "API01.circle at " + std::to_string(x) + ":" + std::to_string(y) +
" - radius: " + std::to_string(radius);
}
};
class DrawingAPI02 : public DrawingAPI {
public:
std::string DrawCircle(float x, float y, float radius) const override {
return "API02.circle at " + std::to_string(x) + ":" + std::to_string(y) +
" - radius: " + std::to_string(radius);
}
};
class Shape {
public:
Shape(const DrawingAPI& drawing_api) : drawing_api_(drawing_api) {}
virtual ~Shape() = default;
virtual std::string Draw() const = 0;
virtual float ResizeByPercentage(const float percent) = 0;
protected:
const DrawingAPI& drawing_api_;
};
class CircleShape: public Shape {
public:
CircleShape(float x, float y, float radius, const DrawingAPI& drawing_api)
: Shape(drawing_api), x_(x), y_(y), radius_(radius) {}
std::string Draw() const override {
return drawing_api_.DrawCircle(x_, y_, radius_);
}
float ResizeByPercentage(const float percent) override {
return radius_ *= (1.0f + percent/100.0f);
}
private:
float x_, y_, radius_;
};
int main(int argc, char** argv) {
std::vector<CircleShape> shapes {
CircleShape{1.0f, 2.0f, 3.0f, DrawingAPI01{}},
CircleShape{5.0f, 7.0f, 11.0f, DrawingAPI02{}}
};
for (auto& shape: shapes) {
shape.ResizeByPercentage(2.5);
std::cout << shape.Draw() << std::endl;
}
return 0;
}
The posted code is buggy -- in particular, the Shape class is holding a reference-to-a-DrawingAPI-object:
class Shape {
[...]
protected:
const DrawingAPI& drawing_api_;
};
... but the object that it is referencing is a temporary that gets destroyed as soon as the CircleShape constructors inside main() return.
One way to avoid the fault would be to declare the DrawingAPI01 and DrawingAPI02 objects in such a way that their lifetimes last longer than the lifetimes of the CircleShape objects that reference them, e.g. by changing main() to look like this:
int main(int argc, char** argv) {
DrawingAPI01 api01; // declaring these up here keeps them valid
DrawingAPI01 api02; // until the end of main()
std::vector<CircleShape> shapes {
CircleShape{1.0f, 2.0f, 3.0f, api01},
CircleShape{5.0f, 7.0f, 11.0f, api02}
};
for (auto& shape: shapes) {
shape.ResizeByPercentage(2.5);
std::cout << shape.Draw() << std::endl;
}
return 0;
}
I am working on a project for understanding classes and have hit a wall. If you have any advice about my syntax, please let me know where I am going wrong as I am still quite new to programming, but my question is to do with class inheritance. (A, C and D are included but pretty well completed).
My project:
A. Start with a point class... Override << (print values), +, - (to add and subtract point coordinates). I feel I have completed this portion.
B. Create a base class Shape. Shape will contain functions to calculate area, circumference and take point values to create a box that encapsulates the given shape. These will be overloaded by derived classes. Create a display() function that displays all relevant info (name, area, circumference and encapsulating box.
C. Build a heirarchy for shapes by making circle, square, triangle... add default and custom constructors whos arguments initialize the shapes using the correct number of point objects. I feel I have satisfied this too.
D. In main() Create an instance of each. Circle radius = to 23, square sides each = 25, Triangle sides = 10, 20 and 30 (very flat triangle, area = 0). Define each to contain the origin (0, 0). Display all the info. I feel I have completed this (minus the display function).
My question is (and where I am struggling), "How do I properly make/access functions from a base class (shape) to return meaningful information."
Do I literally just make them all virtual since some classes dont have the same information as others? (like Area() and Circumference()?)
#include <iostream>
#include <cmath>
using namespace std;
class Point {
public:
int x, y;
Point() {
x = 0;
y = 0;
}
Point(int x, int y): x(x), y(y) {} // constructor
friend ostream& operator<<(ostream& out, const Point number) { //Involves ostream to output the numbers
out << "(" << number.x << ", " << number.y << ")"; //that were input into the x and y values of Point.
return out;
}
friend Point operator+(Point first, Point second) { //Takes two mathematical vectors and tells the compiler
Point add; // to add the x values together and the y values together
add.x = first.x + second.x;
add.y = first.y + second.y;
return add;
}
friend Point operator-(Point first, Point second) { // same as above but with subtraction.
Point subtract;
subtract.x = first.x - second.x;
subtract.y = first.y - second.y;
return subtract;
}
};
class Shape {
protected:
float height, width;
public:
Shape() {
height = 0;
width = 0;
}
Shape(float h, float w) {
height = h;
width = w;
}
/*
int Display() {
//Do something..... Create a display function
return 0;
}
int BoundingBox() {
//Do something again......
return 0;
}
*/
virtual float Area() const = 0;
virtual float Circumference() const = 0;
virtual ~Shape() {};
};
class Circle: public Shape {
Point center;
float radius;
public:
Circle(): Shape() {};
Circle (Point p1, float r) { //Takes center point object, and given radius.
center = p1;
radius = r;
}
virtual float Area() const override { // Calculates circle area
return(M_PI * radius * radius);
}
virtual float Circumference() const override { // Calculates circumference
return(float (M_PI * 2 * radius));
}
virtual ~Circle() {};
};
class Square: public Shape {
Point first, second, third, fourth;
public:
Square(): Shape() {};
Square(Point p1, Point p2, Point p3, Point p4) { // Takes four point arguments and initializes them
first = p1;
second = p2;
third = p3;
fourth = p4;
height = second.x - first.x; //calculates the height and width from points
width = third.y - first.y;
}
virtual float Circumference() const override {
return 0; //Errors without the return statement
}
virtual float Area() const override{ // Calculates area by measuring the difference between given points
return(height * width);
}
virtual ~Square() {};
};
class Triangle: public Shape {
Point first, second, third;
public:
Triangle(): Shape() {};
Triangle(Point p1, Point p2, Point p3) { // Takes three point arguments and initializes them
first = p1;
second = p2;
third = p3;
height = third.y - first.y;// due to the nature of the question, this only works for flat triangles.
width = second.x - first.x;
}
virtual float Circumference() const override {
return 0; //Errors without the return statement
}
virtual float Area() const override {
return ((height * width) / 2);
}
virtual ~Triangle() {};
};
int main() {
Point p1(0, 0), p2(25, 0), p3(0, 25), p4(25, 25), p5(20, 0), p6(30, 0);
Circle c1 (p1, 23); // Circle with origin (0, 0) and a radius of 23
Square s1 (p1, p2, p3, p4); // Square with 4 points and the origin
Triangle t1 (p1, p5, p6); // Extraordinarily flat triangle with origin
cout << c1.Circumference() << endl;
cout << s1.Area() << endl;
cout << t1.Area() << endl;
}
At this point, I am feeling a bit lost of the woods and I am sure I have either created several mistakes along the way, or just a few, but regardless, I don't understand. Any advice would be appreciated!
edit: I have updated my code to include the recommendations to include virtual deconstructors, remove the getheight etc... statements, and add virtual to the derived functions
When you're working with inheritance, make sure to use a virtual destructor in all of your inherited classes, as well as the base class.
Your inherited virtual functions would benefit from being marked virtual and override too, in case you want to make further specializations.
You are overriding inherited functions, but then they do the same thing as the original, e.g. GetHeight(). That kinda defeats the point of inheriting those functions. They also do not need to be virtual if they aren't overridden.
Your derived classes would benefit from explicitly calling the base class's constructor. It will call the default constructor if you don't provide a specific constructor to call, which may or may not be the behaviour you intended - IMO it's safer to always provide the base class constructor you want!
As an example:
class Shape {
protected:
float height, width;
public:
Shape() {
height = 0;
width = 0;
}
Shape(float h, float w) {
height = h;
width = w;
}
virtual float Area() const = 0;
virtual float Circumference() const = 0;
virtual ~Shape() {};
};
class Circle: public Shape {
Point center;
float radius;
public:
Circle() : Shape() {};
Circle (Point p1, float r) : Shape() {
// Note you may wish to set the height and width here!
//Takes center point object, and given radius.
center = p1;
radius = r;
}
virtual float Area() const override { // Calculates circle area
return(M_PI * radius * radius);
}
virtual float Circumference() const override { // Calculates circumference
return(float (M_PI * 2 * radius));
}
virtual ~Circle() {};
};
This question already has answers here:
What is object slicing?
(18 answers)
Closed 5 years ago.
Hey guys here is some code I am going to run, issue is it doesn't work the way I intend to. I am unable to figure out what's wrong with it. I am c++ noob please help.
#include <iostream>
#include <cmath>
#include <stdexcept>
using namespace std;
/**
* Super class
*/
class Shape
{
protected:
int _dimensions;
public:
Shape() : _dimensions{0}
{};
Shape(int dims) : _dimensions{dims}
{};
virtual double getArea() {};
// Because some shapes have no volume.
virtual double getVolume() {};
void setDimensions(int dim)
{
this->_dimensions = dim;
};
int getDimensions()
{
return this->_dimensions;
};
};
/**
* Extended classes
*/
class TwoDimensionalShape : public Shape
{
public:
TwoDimensionalShape() : Shape{2}
{};
// This should throw an error
double getVolume() {
throw logic_error("This shape ain't got area!");
};
};
class ThreeDimensionalShape : public Shape
{
public:
ThreeDimensionalShape() : Shape{3} {};
};
/**
* Final Concrete classes extending extended classes
*/
class Circle : public TwoDimensionalShape
{
protected:
double _radius;
public:
Circle(double r) : _radius{r}
{};
double getArea()
{
// pi*r^2
return M_PI * pow(_radius, 2);
}
};
class Square : public TwoDimensionalShape
{
protected:
double _side;
public:
Square(double s) : _side{s}
{}
double getArea()
{
// s^2
return pow(_side, 2);
}
};
class Triangle : public TwoDimensionalShape
{
protected:
double _base, _height;
public:
Triangle(double b, double h) : _base{b}, _height{h}
{};
double getArea()
{
// b*h/2
return _base * _height / 2;
}
};
class Sphere : public ThreeDimensionalShape
{
protected:
double _radius;
public:
Sphere(double r) : _radius{r}
{}
double getArea()
{
cout << 4 * M_PI * pow(_radius, 2) << endl;
return 4 * M_PI * pow(_radius, 2);
}
double getVolume()
{
return (4/3) * M_PI * pow(_radius, 3);
}
};
class Cube : public ThreeDimensionalShape
{
protected:
double _side;
public:
Cube(double s) : _side{s}
{};
double getArea()
{
// surface area = 6*a^2
return 6 * pow(_side, 2);
}
double getVolume()
{
// a^3
return pow(_side, 3);
}
};
class Tetrahedron : public ThreeDimensionalShape
{
protected:
double _side;
public:
Tetrahedron(double s) : _side{s}
{};
double getArea()
{
// sqrt(3)*a^2
return sqrt(3) * pow(_side, 2);
}
double getVolume()
{
// a^3/6sqrt(2)
return pow(_side, 3) / (6 * sqrt(2));
}
};
int main()
{
Shape arr[2];
arr[0] = Circle{10};
arr[1] = Sphere{10};
// This one is accessing the right method.
cout << "Area of circle: " << arr[0].getArea() << endl;
// This one should access the parent, but accesses the grand parent!
// even if it is overridden in parent.
cout << "Volume of circle: " << arr[0].getVolume() << endl;
// Both of these are accessing methods on grand parent rather than their own!!
cout << "Area of sphere: " << arr[1].getArea() << endl;
cout << "Volume of sphere: " << arr[1].getVolume() << endl;
return 0;
}
I don't know why the array methods keep accessing the grand parent functions in the last three lines, but the right method on the first.
You are experiencing Object Slicing. The portion of your code below does that:
Shape arr[2];
arr[0] = Circle{10};
arr[1] = Sphere{10};
Each of the assignments above invokes the copy assignment operator of Shape and slices off objects of the subclass. You can achieve your intention by using references or pointers:
std::unique_ptr<Shape> arr[2];
arr[0] = std::make_unique<Circle>(10);
arr[1] = std::make_unique<Sphere>(10);
This is a case of object slicing. You need to put your objects as pointers, preferably as std::unique_ptr<> into your array - or again preferably a std::vector<>
Try this:
#include <memory>
#include <vector>
// ...
int main()
{
std::vector<std::unique_ptr<Shape>> vec(2);
vec[0] = std::make_unique<Circle>(10);
vec[1] = std::make_unique<Sphere>(10);
// This one is accessing the right method.
cout << "Area of circle: " << vec[0]->getArea() << endl;
// This one should access the parent, but accesses the grand parent!
// even if it is overridden in parent.
cout << "Volume of circle: " << vec[0]->getVolume() << endl;
// Both of these are accessing methods on grand parent rather than their own!!
cout << "Area of sphere: " << vec[1]->getArea() << endl;
cout << "Volume of sphere: " << vec[1]->getVolume() << endl;
return 0;
}
I dont understand the diffrence between Polymorphism and Inheritance... They Litterarly do the same thing...
Simple Example Of Polymorphism:
class shape {
public:
void setValues(int height_, int width_) {
height = height_, width = width_;
}
protected:
int height, width;
private:
};
class rectangle :public shape, public ThreeDView{
public:
int area() {
return(shape::height*shape::width);
}
float threeDArea() {
return(((shape::height*shape::width)/2)*(std::cos(Z_LENGTH)));
}
};
class ThreeDView{
public:
void setZLength(int value) {
Z_LENGTH = value;
}
int setCompact(bool ans) {
compact = ans;
}
float getZLength() {
return Z_LENGTH;
}
bool getCOMPACT() {
return compact;
}
protected:
float Z_LENGTH;
bool compact;
private:
unsigned char ZCHAR = 'Z';
};
class triangle :public shape {
public:
int area() {
return((shape::height * shape::width) / 2);
}
};
int main(){
rectangle rect2;
triangle trng2;
shape *poly = &rect2;
shape *poly2 = &trng2;
poly->setValues(2,3);
poly2->setValues(5,4);
std::cout << "AREA : " << trng1.area() << "AREA RECT : \n" <<rect1.area() << std::endl;
}
Above example translated to Inheritance:
class shape {
public:
void setValues(int height_, int width_) {
height = height_, width = width_;
}
protected:
int height, width;
private:
};
class rectangle :public shape, public ThreeDView{
public:
int area() {
return(shape::height*shape::width);
}
float threeDArea() {
return(((shape::height*shape::width)/2)*(std::cos(Z_LENGTH)));
}
};
class triangle :public shape {
public:
int area() {
return((shape::height * shape::width) / 2);
}
};
int main(){
rectangle rect2;
triangle trng2;
rect2.setValues(2,3);
trng2.setValues(5,4);
std::cout << "AREA : " << trng1.area() << "AREA RECT : \n" <<rect1.area() << std::endl;
}
Please tell me diffrence. Honestly i dont even see the use of Polymorphism! Thanks for helping!
Here's a version of your first example, that actually uses polymorphism:
#include <iostream>
#include <string>
class shape
{
public:
void setValues(int height_, int width_)
{
height = height_;
width = width_;
}
virtual int area() = 0; // This is needed for polymorphism to work
virtual std::string name() = 0;
protected:
int height;
int width;
};
class rectangle : public shape
{
public:
int area()
{
return height * width;
}
std::string name()
{
return "Rectangle";
}
};
class triangle :public shape
{
public:
int area()
{
return height * width / 2;
}
std::string name()
{
return "Triangle";
}
};
void print_area(shape& poly)
{
std::cout << poly.name() << ' ' << poly.area() << '\n';
}
int main()
{
rectangle rect;
triangle trng;
rect.setValues(2, 3);
trng.setValues(5, 4);
print_area(rect);
print_area(trng);
}
The first big change is that I declare the virtual function area in the shape class. For polymorphism to work, the functions must be declared in the base class as virtual. The "assignment" to 0 is simply telling the compiler that it's an abstract function, and the child-classes must override that function.
The second big change is that I use a function to print the area, one that only takes a reference to the base shape class. You must use references or pointers to the base class for polymrphism to work, not use the actual objects directly like in your example.
This works as expected.
I used the Fireworks init function to store a particle into the particles vector class.
And when I try to retrieve the count of the particles vector in the update() function, the particles vector is empty. Why?
Fireworks.cpp class:
void Fireworks::init(){
float x = randf();
float y = - 1 * randf(); //Going UP
float z = randf();
Particle part(position,Vector3f(x,y,z), color, randInt(1,50));
particles.push_back(part);
}
bool Fireworks::update(){
Particle particle;
int count = particles.size(); //Total num of particles in system
cout << particles.size() << " ";
}
class Fireworks: public ParticleSystem {
private:
void init();
public:
Fireworks(Vector3f pos, Vector3f col) {
position = pos;
color = col;
init();
}
virtual bool update();
};
particlesystem.h
class ParticleSystem {
protected:
vector<Particle> particles;
public:
//virtual Particle generateParticle();
virtual bool update(){return false;};
};
main.cpp
ParticleSystem *PS;
int main( int argc, char *argv[] ) {
PS = &Fireworks(Vector3f(0,0,0), Vector3f(200,0,255));
glutIdleFunc(move);
}
void move()
{
PS->update();
}
PS = &Fireworks(Vector3f(0,0,0), Vector3f(200,0,255));
This introduces undefined behavior. The right hand side creates a temporary, which will be deleted as soon as that full expression is over (i.e. right after the ;). PS will point to a deleted object after that line - doing anything with it is undefined behavior.
Use new.
PS = new Fireworks(Vector3f(0,0,0), Vector3f(200,0,255));
Also, you must return from all functions that are declared as returning something (non-void). It doesn't matter if they're virtual or not.