I was playing around with pointer to the base class, and I casted a rectangle pointer into a circle pointer and called the printradius() function from the rectangle! Could someone explain why this is allowed? Thanks.
#include <iostream>
#include <string>
using namespace std;
class Shape {
};
class Circle: public Shape {
private:
double radius;
public:
Circle(double r)
{ radius = r;}
void printradius()
{ cout << "circle's radius is " << radius << endl;}
};
class Rectangle: public Shape {
private:
double width, length;
public:
Rectangle(double l, double w)
{ length = l; width = w;}
};
int main() {
Rectangle r( 2.0, 2.0); // only a rectangle is created
Shape* s = &r; // up cast into a shape
Circle* c = static_cast<Circle*>(s); //down cast into a circle
c->printradius();
}
output:
circle's radius is 2
What do you mean by "allowed"?
The language explicitly states that the result of such static_cast is undefined, so it is not really "allowed" in this case. In order to perform a valid downcast from Shape * to Circle *, you have to ensure that Shape * actually points to Circle or something derived from Circle. Otherwise, the behavior is undefined.
As for why the compiler did not catch it... The compiler cannot possibly catch errors that depend on run-time conditions. In general case the compiler does not know what your s pointer actually points to.
As for why the language even offers such feature... It offers it because it can be extremely useful when one uses it properly.
The static cast is "because I said so.", in other words, trust me, the programmer, that the thing is what I say it is, a circle pointer in this case. When calling the printradius() method, The this pointer is for r, and when printradius() happens to deref looking for a radius, it finds that first double, with a value of 2.0. There is no crash, or reported error from running this way, but as you know, it makes no sense.
Use a dynamic cast and check the value returned. You will see null, because rectangle and circle are not the same.
Related
I have a 2d physics engine that I've been programming in C++ using SFML; I've implemented a rough collision detection system for all SandboxObjects (the base class for every type of physics object), but I have a dilemma.
I plan to have many different derived classes of SandboxObjects, such as Circles, Rects, and so on, but I want a way to check if the roughHitbox of each SandboxObject collides with another.
When the program starts, it allocates memory for, let's say, 10,000 Circles
int circleCount = 0;//the number of active Circles
constexpr int m_maxNumberOfCircles = 10000;//the greatest number of circles able to be set active
Circle* m_circles = new Circle[m_maxNumberOfCircles];//create an array of circles that aren't active by default
like so.
and every time the user 'spawns' a new Circle, the code runs
(m_circles + circleCount)->setActive();`
circleCount++
Circles that aren't alive essentially do not exist at all; they might have positions and radii, but that info will never be used if that Circle is not active.
Given all this, what I want to do is to loop over all the different arrays of derived classes of SandboxObject because SandboxObject is the base class which implements the rough hitbox stuff, but because there will be many different derived classes, I don't know the best way to go about it.
One approach I did try (with little success) was to have a pointer to a SandboxObject
SandboxObject* m_primaryObjectPointer = nullptr;
this pointer would be null unless there were > 1 SandboxObjects active; with it, I tried using increment and decrement functions that checked if it could point to the next SandboxObject, but I couldn't get that to work properly because a base class pointer to a derived class acts funky. :/
I'm not looking for exact code implementations, just a proven method for working with the base class of many different derived classes.
Let me know if there's anything I should edit in this question or if there's any more info I could provide.
Your problems are caused by your desire to use a polymorphic approach on non-polymorphic containers.
The advantage of a SandboxObject* m_primaryObjectPointer is that it allows you to treat your objects polymorphicaly: m_primaryObjectPointer -> roughtHitBox() will work regardless of the object's real type being Circle, Rectangle, or a Decagon.
But iterating using m_primaryObjectPointer++ will not work as you expect: this iteration assumes that you iterate over contiguous objects in an array of SandboxObject elements (i.e. the compiler will use the base type's memory layout to compute the next address).
Instead, you may consider iterating over a vector (or an array if you really want to deal with extra memory management hassle) of pointers.
vector<SandboxObject*> universe;
populate(universe);
for (auto object:unviverse) {
if (object->isActive()) {
auto hb = object -> roughtHitBox();
// do something with that hitbox
}
}
Now managing the objects in the universe can be painful as well. You may therefore consider using smart pointers instead:
vector<shared_ptr<SandboxObject>> universe;
(little demo)
It's hard to answer this without knowing the requirements but you could have sandbox maintain two vectors of active and inactive objects, and use unique_ptrs of the base class for memory management.
Some code below:
#include <vector>
#include <memory>
#include <iostream>
class sandbox_object {
public:
virtual void do_something() = 0;
};
class circle : public sandbox_object {
private:
float x_, y_, radius_;
public:
circle(float x, float y, float r) :
x_(x), y_(y), radius_(r)
{}
void do_something() override {
std::cout << "i'm a circle.\n";
}
};
class triangle : public sandbox_object {
private:
float x1_, y1_, x2_, y2_, x3_, y3_;
public:
triangle( float x1, float y1, float x2, float y2, float x3, float y3) :
x1_(x1), y1_(y1), x2_(x2), y2_(y2), x3_(x3), y3_(y3)
{}
void do_something() override {
std::cout << "i'm a triangle.\n";
}
};
class sandbox {
using sandbox_iterator = std::vector<std::unique_ptr<sandbox_object>>::iterator;
private:
std::vector<std::unique_ptr<sandbox_object>> active_objects_;
std::vector<std::unique_ptr<sandbox_object>> inactive_objects_;
public:
void insert_circle(float x, float y, float r) {
active_objects_.push_back( std::make_unique<circle>(x, y, r) );
}
void insert_triangle(float x1, float y1, float x2, float y2, float x3, float y3) {
active_objects_.push_back( std::make_unique<triangle>(x1,y1,x2,y2,x3,y3));
}
sandbox_iterator active_objs_begin() {
return active_objects_.begin();
}
sandbox_iterator active_objs_end() {
return active_objects_.end();
}
void make_inactive(sandbox_iterator iter) {
std::unique_ptr<sandbox_object> obj = std::move(*iter);
active_objects_.erase(iter);
inactive_objects_.push_back(std::move(obj));
}
};
int main() {
sandbox sb;
sb.insert_circle(10.0f, 10.0f, 2.0f);
sb.insert_triangle(1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 1.0f);
sb.insert_circle(1.0f, 6.0f, 4.0f);
sb.make_inactive(sb.active_objs_begin());
(*sb.active_objs_begin())->do_something(); // this should be the triangle...
return 0;
}
I've been given a task for my cpp homework, the task is long and has many more functions that this, but I am stuck at the beggining. What I am trying to do here is just write out the point that is given on the screen.
#include <iostream>
using namespace std;
class Point {
public:
double x, y;
Point(){
x=0.0;
y=0.0;
};
Point(double x,double y){
this -> x = x;
this -> y = y;
}
void print() {
cout << "(x,y) = ("<< x <<","<< y <<")"<<endl;
}
};
class Triangle {
public:
Point A;
Triangle(const Point& p1){
A.x = p1.x;
A.y = p1.y;
}
void print1(){
cout << "A(x,y) = ("<< A.x <<","<< A.y <<")"<<endl;
}
};
int main(){
Triangle A{1.0,2.0};
A.print1();
return 0;
}
What my thinking here is, I have a class named Point and it is made of two variables x and y, class Triangle in the task has 3 points, but I am using just one for simplicity, it has a point that is from class Point (so it should have x and y coordinates) and a constructor that has a point from class Point also. I was thinking just to link their x and y coordinates and to print them out. But it doesn't work like that, can you help me. I have more code from the task if you need, and code from our lessons. Thank you.
Triangle(const Point& p1) accepts a const reference to a Point. A reference is an alias to an existing variable. In this case rather than copying in a Point, the Triangle constructor receives the Point itself. The const is important because it is a promise that the Point will not be modified inside by Triangle's constructor. This allows you to pass in a reference to a temporary Point that otherwise would not be around long enough for modification to be meaningful and is rejected by the compiler to prevent possible errors.
Triangle A{1.0,2.0};
will attempt to make Triangle from two floating point values. Triangle needs a reference to a Point, so you must make that Point first.
Triangle A{ {1.0,2.0} };
^ ^
| Construct a temporary Point from 2 floating point numbers
Triangle constructor arguments: one Point
Unrelated improvement: Use the Member Initializer List
Triangle(const Point& p1): A{p1}{
}
// Example program
#include <iostream>
#include <string>
using namespace std;
class circle {
private:
double r;
double const pi=3.14;
public:
circle(double rad){
r=rad;
}
void periArea(){
double p,s;
p=2*pi*r;
s=pi*pi*r;
cout<<"\nS= "<<s<<endl;
cout<<"\nP= "<<p<<endl;
}
friend void changeRad(circle circle, double newrad);
};
void changeRad(circle circle, double newrad){
circle.r=newrad;
}
int main()
{
double inpr,newr;
cout<<"input radius: ";
cin>>inpr;
circle c1(inpr);
c1.periArea();
cout<<"\ninput new radius: ";
cin>>newr;
changeRad(c1,newr);
c1.periArea();
}
I've got this cpp code that has to define a class circle that calculates perimeter and area then using a friend function change the radius and calculate the area and perimeter again. However I get the same p and s values even after the change function.
Crudely, you need to change your function to pass the circle by reference:
void changeRad(circle& circle, double newrad){
(Note the use of &). Otherwise a copy of the circle instance is passed to the function and any changes to that copy will not be reflected in the original.
But, the normal way of doing things is to arrange your code so that you use
c1.changeRad(newr);
at the call site.
Also, your use of a double to store pi to just 3 significant figures is pretty terrible. My favourite way is to use
const double PI = std::atan(1.0) * 4;
since the C++ standard does not define pi for you (M_PI is POSIX, not ISO!).
You have to pass an object the type Circle by reference
friend void changeRad( circle &circle, double newrad);
^^^
Take into account that though it is a valid declaration of a parameter when its name coincides with the name of the type nevertheless this can confuse the reader and the name of the parameter hides the name of the type. So it is better to rename the name of the parameter as for example
friend void changeRad( circle &c, double newrad);
^^
Also it is better to make the function a non-static member of the class. For example
void changeRad( double newrad );
I am creating an abstract geometry class that has children classes. However, I want that the class RightCircularCone also has its own private variables that define its apex coordinates, such that the abstract class is not unnecessary big in memory size for objects of type Sphere that don't need storage of apex variables.
However, I can't seem to access the functions and variables of RightCircularCone when I load them from a container that uses smart pointers, as it keeps being defined as its parent class Shape. Can anyone see what is going wrong?! Appreciate it!
/* shapes.hpp */
class Shape{
public:
unsigned int color;
float radius;
float x,y,z;
public:
void SetSpatial(float radius, float x, float y, float z);
unsigned int GetColor(void);
void SetColor(unsigned int color);
virtual bool PointInside(const std::array<double,3> &point)=0;
};
class RightCircularCone : public Shape{
private:
float Ax,Ay,Az;
public:
bool PointInside(const std::array<double,3> &point);
void SetApex(float x, float y, float z);
void PrintApex();
};
class Sphere : public Shape{
public:
bool PointInside(const std::array<double,3> &point);
};
The classes defined above are used in another .cpp file where methods of a class are defined:
#include "../../include/part.hpp" /* includes shapes.hpp in turn */
void Part::ReadPartFile(std::string partfile){
try{
std::ifstream dataFile;
dataFile.open(partfile);
//do checks, error badbits etc...
std::string word;
unsigned int counter=0;
while(!dataFile.eof()){
dataFile >> word;
if(word == "sphere"){
auto newSphere = std::make_shared<Sphere>();
// load variables into objects from file by checking each word by using setColor and setSpatial
shapeList[counter++] = newSphere;
} else if(word == "rccone"){
auto newRccone = std::make_shared<RightCircularCone>();
// load variables into objects from file by checking each word by using setColor and setSpatial and setApex
shapeList[counter++] = newRccone;
}
}
dataFile.close();
} catch(std::ifstream::failure e) {
//do exception handling here if necessary
}
Now, when I use an iterator over the map std::map<unsigned int, std::shared_ptr<Shape> > shapeList; as defined in part.cpp I can never access the methods of children classes Sphere and RightCircularCone as the map returns a type of Shape, even though I used a smart pointer!!!
Anybody knows why and a potential fix (or neater way to set up the classes)??
Thanks!
//EDIT:
This is the error I get:
error: no member named 'PrintApex' in 'Shape'
iterator->second->PrintApex();
Think about it. You create a vector of shared_ptr of Shape. As far as the vector is concerned you are storing Shape instances in it, not Sphere or whatever.
Now, you happen to initialize your Shape instance with a Sphere and you store the ptr of that Sphere into the vector. Next item is a RightCircularCone, again stored as a Shape.
You access the first element, and as far as the compiler is concerned at THAT point, you only have a Shape. It cannot deduce the actual type as this happens at runtime. So, as far as the compiler is concerned you have a Shape instance with whatever the Shape class contains.
Now, you need to somehow inform the compiler about the type you want to work with, so it can find the methods you want to access. For that, you use dynamic_cast to specify the intent that this is a Sphere and you should have access to Sphere members.
More details about dynamic_cast, here http://en.cppreference.com/w/cpp/language/dynamic_cast
Edit. A note about design.
In principle, you want to offload as much to the compiler. If there is something that compiler can do, let him do it. So, if you want to do something different for each subclass of Shape, instead of checking a string literal for the Shape type you could use virtual specialized functions that act on a specific type. E.g.
virtual void printMe(Sphere & sphere) {
cout << "This is a sphere with radious x" << endl;
}
virtual void printMe(RightCircularCone & cone) {
cout << "This is a cone" << endl;
}
//and you use like
for (auto & shape: shapes) { printMe(shape); }
//and the correct functions are resolved automagically
it may seem a bit more work, but in the long run it is actually simpler as you offload the picking of the functionality to someone else.
Is the Wikipedia example at this article about method overiding in C++ correct?
Please see the code below where I have mentioned a comment //INCORRECT
Slightly confused about overiding in C++ and run time polymorphism. What should this cast do?
#include <iostream>
class Rectangle {
public:
explicit Rectangle(double l, double w) : length(l), width(w) {}
virtual void print() const;
private:
double length;
double width;
};
void Rectangle::print() const { // print() method of base class
std::cout << "Length = " << this->length << "; Width = " << this->width;
}
class Box : public Rectangle {
public:
explicit Box(double l, double w, double h) : Rectangle(l, w), height(h) {}
virtual void print() const; // virtual is optional here, but it is a good practice to remind it to the developer
private:
double height;
};
void Box::print() const { // print() method of derived class
Rectangle::print(); // Invoke parent print() method.
std::cout << "; Height= " << this->height;
}
int main(int argc, char** argv) {
Rectangle rectangle(5.0, 3.0); rectangle.print();
// outputs:
// Length = 5.0; Width = 3.0
Box box(6.0, 5.0, 4.0);
// the pointer to the most overridden method in the vtable in on Box::print
//box.print(); // but this call does not illustrate overriding
static_cast<Rectangle&>(box).print(); // this one does
// outputs:
// Length = 5.0; Width = 3.0; Height= 4 // INCORRECT
//But it actually outputs Length = 6; Width = 5; Height = 4
getchar();
return 0;
}
You're right - the output mentioned is incorrect.
The cast simply demonstrates that a box is a kind of rectangle (inheriting from it) and that even as a rectangle, the method override will still be effective and the Box version of the print method will be called.
Feel free to fix the comment in Wikipedia: the output should indeed be Length = 6; Width = 5; Height = 4.
The other part is correct, though: the code where a Box.print() is called even after the Box reference has been statically cast to a reference to its superclass is indeed a demonstration of how overriding of a virtual method works in C++.
Another way to demonstrate the same point is through use of a pointer instead of a reference:
Rectangle *boxPtr = &box;
boxPtr->print();
this line: static_cast<Rectangle&>(box).print(); has same effect as this code would have:
Rectangle & r = box;
r.print();
and also same effect as this code would have:
Rectangle * r = &box;
r->print();
It means that Box object was created (Box box(6.0, 5.0, 4.0); = in runtime you see Box) and it doesn't matter what is the type of pointer / reference where you store this object. The fact that you store box as a Rectangle* is what you see in compile time.
Most important fact about overriding virtual methods is that about "which method will be called?" is decided in runtime.
Hope this helps.
The comment in the article was indeed wrong (and has now been fixed); it should have printed 6,5, and 4 as you say.
The point of the cast is to demonstrate that, even if you call the virtual function via a reference to the base class (Rectangle), it will call the override associated with the actual type of the object (Box) - you still get the three values printed by Box::print(), rather than the two printed by Rectangle::print().