Why is virtual function not being called? - c++

//GUITEXT
class guitext : public entity {
public:
guitext(graphics *gfx, std::string _text, float _x, float _y,
float _size, float timeToLive);
bool update(float deltaTime, gameworld *world);
void draw(graphics *gfx);
};
void guitext::draw(graphics *gfx) { printf("draw"); }
//ENTITY
class entity {
public:
virtual bool update(float deltaTime, gameworld *world)
{ return false; }
virtual void draw(graphics *gfx) { }
};
//GAMEWORLD
void gameworld::addEntity(entity e) { entitys.push_back(e); }
//MAIN
for(int i = 0; i < (int)entitys.size(); i++) { entitys[i].draw(gfx); }
I have a vector in my gameworld class. When I add push a guitext entity to this vector I expect it to call the guitext::draw() function. But the base class function is being called. What am I doing wrong?

You made a vector of entity. Those objects always have type entity. If you want to invoke polymorphism, they need to be pointers or references. How can a vector of entity store a guitext? There's not enough space, it doesn't know how to destroy it, etc etc.

Was the vector declared as vector<entity>? Then only the base class part can be stored there, i.e. you lose polymorphism (which only works through pointer or reference in C++).

What you've done is a bit concealed variant of slicing.

You should define entitys to contain pointers to entity. Slightly edited example derived from your code.
#include "stdafx.h"
#include <vector>
#include <string>
class entity
{
public:
virtual void draw() { }
};
class guitext : public entity
{
public:
void draw()
{
printf("draw");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<entity *> entitys;
guitext g;
entitys.push_back(&g);
for(int i = 0; i < (int)entitys.size(); i++)
{
entitys[i]->draw();
}
return 0;
}

You're storing Entitys, not pointers to objects of varying derived types of Entity.

In addition, in your case it's not good idea to pass arguments by value, i suppose there will be very big quantity of objects that need to be redrawed. Better, by const reference, since functon doesn't change state of passed object inside.

Related

Manage abstract classes in std container

After a lot of research I still don't understand how to deal with an abstract class collection with smart pointers.
Here are the errors I got:
error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Shape; _Dp = std::default_delete<Shape>]'
base_ptr s = shapes.front();
error: no matching function for call to 'std::unique_ptr<Shape>::unique_ptr(Shape&)'
shapes.push(base_ptr(b));
By compiling the minimal code to replicate the error (code online avaiable).
#include <queue>
#include <memory>
class Shape {
public:
virtual int getPerimeter() =0;
};
typedef std::unique_ptr<Shape> base_ptr;
class Circle : public Shape {
public:
virtual int getPerimeter() { return 1; };
};
class Square : public Shape {
public:
virtual int getPerimeter() { return 0; };
};
class ShapeManager {
public:
ShapeManager();
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
base_ptr s = shapes.front();
s->getPerimeter();
shapes.pop();
}
void submitShape(Shape &b) {
shapes.push(base_ptr(b));
}
private:
std::queue<base_ptr> shapes;
};
int main(int argc, char **argv) {
ShapeManager s();
Circle c;
s.submitShape(c);
s.useShape();
return 1;
}
It works if I declare the queue as queue<Shape*> but I don't want to deal with pointers -meaning *.
EDIT, this code compiles. Thanks everyone. This article suggested by Guillaume Racicot helps seeing clearer the situation.
#include <queue>
#include <memory>
class Shape {
public:
virtual int getPerimeter() =0;
};
typedef std::unique_ptr<Shape> base_ptr;
class Circle : public Shape {
public:
Circle() {};
virtual int getPerimeter() { return 1; };
};
class Square : public Shape {
public:
virtual int getPerimeter() { return 0; };
};
class ShapeManager {
public:
ShapeManager();
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
base_ptr s = std::move(shapes.front());
s->getPerimeter();
shapes.pop();
}
void submitShape(base_ptr b) {
shapes.push(std::move(b));
}
private:
std::queue<base_ptr> shapes;
};
int main(int argc, char **argv) {
ShapeManager s;
base_ptr c = std::make_unique<Circle>();
s.submitShape(std::move(c));
s.useShape();
return 1;
}
The container is a distraction. The problem is that unique_ptr is not copyable; if it were, it wouldn't be unique. So you probably need to add a call to std::move:
base_ptr s = std::move(shapes.front());
This means something different from what the original code might have been intended to do; it removes the object from the container. If that's not what you wanted, then std::move isn't the right answer and, probably, unique_ptr is not the right mechanism.
There are many problems in your example, not just misuse of smart pointers. First, the most obvious once is your declaration of s:
ShapeManager s();
This declares a function named s that returns a ShapeManager and takes no parameter.
Maybe you meant to declare an object of type ShapeManager?
ShapeManager s{};
// Or
ShapeManager s;
Secondly, you are misusing smart pointer. You have a queue of unique pointer. A unique pointer is a RAII wrapper around a free store allocated object. That means that it's a wrapper that is constructed with an object allocated with new. In your example, you're not doing that. You are constructing unique pointer with an object that has automatic storage.
A smart pointer that points to a automatic storage allocated object is the observer pointer: is must not own, delete or try to manage anything about that object. In fact, observer pointer is a language feature instead of a library one. It's commonly called a pointer.
This is your code with usage of observer pointers:
template<typename T>
using observer_ptr = T*;
struct ShapeManager {
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
auto s = shapes.front();
s->getPerimeter();
shapes.pop();
}
void submitShape(Shape &b) {
shapes.push(&b);
}
private:
std::queue<base_ptr> shapes;
};
int main() {
ShapeManager s;
Circle c; // Automatic storage
Rectangle r; // Automatic storage too.
s.submitShape(c);
s.submitShape(r);
s.useShape();
}
However, you might not want to hold them using automatic storage. My guess is you want to use std::unique_ptr everywhere instead. This allow the object submitted to the shape manager to outlive it's scope. For that you'll need to allocate objects on the free store. The most common way is to use std::make_unique:
struct ShapeManager {
void useShape() {
if(shapes.empty())
throw "Work stack is empty.";
// We must create a reference,
// Using simply auto would require copy,
// Which is prohibited by unique pointers
auto&& s = shapes.front();
s->getPerimeter();
shapes.pop();
}
void submitShape(base_ptr b) {
shapes.push(std::move(b));
}
private:
std::queue<base_ptr> shapes;
};
int main() {
ShapeManager s;
// Allocated on the free store,
// The lifetime of c and r are managed by
// The unique pointer.
auto c = std::make_unique<Circle>();
auto r = std::make_unique<Rectangle>();
s.submitShape(std::move(c));
s.submitShape(std::move(r));
s.useShape();
}

Whether using dynamic cast for providing input for derived class virtual function is recommended?

I read some of the answers in What is the proper use case for dynamic_cast.
The line which best matched my situation here is
#include<iostream>
class Shape
{
public:
virtual void draw()=0;
virtual ~Shape(){};
};
class Rectangle : public Shape
{
public:
int length;
int breath;
void draw()
{
std::cout<<"RECTANGE"<<std::endl;
}
};
class Circle : public Shape
{
public:
int diameter;
void draw()
{
std::cout<<"CIRCLE"<<std::endl;
}
};
/*Abstract Factory*/
Shape* getShapeObj(int type)
{
switch(type)
{
case 1:
return new Rectangle;
case 2:
return new Circle;
/* many types will be added here in future. */
}
return NULL;
};
void drawShapes(Shape *p_shape[],int len)
{
for(int i=0;i<len;i++)
p_shape[i]->draw();
}
int main()
{
Shape *l_shape[2];
l_shape[0]=getShapeObj(1);
l_shape[1]=getShapeObj(2);
Rectangle *l_rec=dynamic_cast<Rectangle*>(l_shape[0]);
if(l_rec)
{
l_rec->length=10;
l_rec->breath=20;
}
Circle *l_circle=dynamic_cast<Circle*>(l_shape[1]);
if(l_circle)
l_circle->diameter=25;
drawShapes(l_shape,2);
}
Essentially, virtual functions only work in some cases, not all of them.
My problem is to pass the input for the virtual function and inputs will vary from type to type. Whether using dynamic cast is recommended here?
The solution is perfect forwarding of function parameters, introduced in c++11.
template<typename ...CtorArgs>
Shape* getShapeObj(int type, CtorArgs&& ctor_args...)
{
switch(type)
{
case 1:
return new Rectangle(std::forward<CtorArgs>(ctor_args)...);
// many types will be added here in future.
}
return NULL;
}
Obviously making the function a template, defeats the purpose of hiding the hierarchy (as well as forcing rather strict requirements on the number of parameters to the constructors). But if the base contains a map of functions that do the construction, which each derived class updates with a pointer to function that constructs it, you can still have information hiding.
I have recently written an answer about storing type erased function pointers in a map, with some static type checking forwarded to run time.
In this particular case, looks like your main function is taking too much responsibility. What if you have Circle, Hexagon, MyFancyFigure types? All of them should be initialized in main in different branches?
It would be much better to move that "initialization" logic to a separate virtual function init in your classes (or even to the constructor). The code would look like this:
class Shape
{
public:
virtual void draw()=0;
virtual void init()=0;
virtual ~Shape(){};
};
class Rectangle : public Shape
{
public:
int length;
int breath;
void draw()
{
//Draw Rectangle
}
void init()
{
length = 10;
breath = 20;
}
};
int main()
{
Shape *l_shape=getShapeObj(1);
// Calls different code of "init" method depending on the actual object type
l_shape->init();
l_shape->draw();
delete l_shape;
}
Also, please note that this initialization logic may be place in some other place, like constructor of the class or the factory method. But main is definitely the wrong place.

Polymorphism with new data members

I would like to write a function that can initialize and return objects of different classes using polymorphism. I also would like these classes to have different data members which may be called through the virtual function. What I wrote below might work. Could you check if I have some undefined behavior in there? Thank you! One thing I am worried about is that when I call "delete polypoint" at the end it will not free the data member "scale" that is unique to "CRectangle". If my code doesn't work is there a way to make it work?
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area ()
{ return (0); }
};
class CRectangle: public CPolygon {
public:
int scale;
int area ()
{ return (width * height * scale ); }
};
CPolygon *polytestinner()
{
CPolygon *polypoint = 0;
int consoleinput = 2;
if (consoleinput>1)
{
CRectangle *rectpoint = new CRectangle();
rectpoint->scale = 4;
polypoint = rectpoint;
}
polypoint->set_values(3,4);
return polypoint;
}
void polytest()
{
CPolygon *polypoint = polytestinner();
gstd::print<int>(polypoint->area());
delete polypoint;
}
int main()
{
polytest();
return 0;
}
Thank you!
I feel compelled to point out Andrei Alexandrescu's object factory architecture. It allows your architecture to grow without having to modify the factory every time you create a concrete type. It is based on a "callback register", and it is actually implemented as a generic component in some libraries. The code is below.
Live Code Example
#include<map>
#include<iostream>
#include<stdexcept>
// your typical base class
class Shape {
public:
virtual void Draw() const = 0;
// virtual destructor allows concrete types to implement their own
// destrucion mechanisms
virtual ~Shape() {}
};
// this factory architecture was suggested by Andrei Alexandrescu in
// his book "Modern C++ Design" --- read it to get the full
// explanation (and a more generic implementation); this is just an
// example
class ShapeFactory {
public:
// this typedef allows to "name" arbitrary functions which take no
// arguments and return a pointer to a Shape instance
typedef Shape* (*CreateShapeCallback)();
Shape* CreateShape(int ShapeId) {
// try to find the callback corresponding to the given shape id;
// if no shape id found, throw exception
CallbackMap::const_iterator it = m_callbacks.find(ShapeId);
if(it == m_callbacks.end()) {
throw std::runtime_error("unknown shape id");
} else {
// create the instance using the creator callback
return (it->second)();
}
}
bool RegisterShape(int ShapeId, CreateShapeCallback Creator) {
// returns true if shape was registered; false if it had already
// been registered
return m_callbacks.insert(CallbackMap::value_type(ShapeId, Creator)).second;
}
bool UnRegisterShape(int ShapeId) {
// returns true if shape was unregistered, false if it was not
// registered in the first place
return m_callbacks.erase(ShapeId) == 1;
}
private:
// the typedef simplifies the implementation
typedef std::map<int, CreateShapeCallback> CallbackMap;
// the callbacks are stored in a map int->callback (see typedef
// above)
CallbackMap m_callbacks;
};
// create some concrete shapes... you would do this in other CPP files
class Line : public Shape {
public:
void Draw() const {
std::cout<<"Drawing a line"<<std::endl;
}
};
// another concrete shape...
class Circle : public Shape {
public:
void Draw() const {
std::cout<<"Drawing a circle"<<std::endl;
}
};
// ... other concrete shapes...
enum ShapeIds {LINE=1, CIRCLE, COUNT};
Shape* CreateLine() { return new Line; }
Shape* CreateCircle() { return new Circle; }
int main() {
// suppose this is the "singleton" instance for the ShapeFactory
// (this is an example! Singletons are not implemented like this!)
ShapeFactory *factory = new ShapeFactory;
factory->RegisterShape(ShapeIds::LINE, CreateLine);
factory->RegisterShape(ShapeIds::CIRCLE, CreateCircle);
Shape* s1 = factory->CreateShape(ShapeIds::CIRCLE);
Shape* s2 = factory->CreateShape(ShapeIds::LINE);
s1->Draw();
s2->Draw();
// will throw an error
try {
Shape *s3 = factory->CreateShape(-1);
s3->Draw();
} catch(const std::exception& e) {
std::cout<<"caught exception: "<<e.what()<<std::endl;
}
return 0;
}
CPolygon needs a virtual destructor:
virtual ~CPolygon() {}
You have undefined behavior in your code:
CPolygon *polypoint;
delete polypoint;
deleting a base class pointer when there is no virtual destructor will result in undefined behavior.
Your CPolygon class and CRectangle classes have no destructors, though the compiler will generate default destructor for you in this case, but they are not virtual by default. Therefore, you need to at least define a virtual destructor for your base class, i.e., CPolygon.

Mapped functors to member functions losing scope

I'd like to be able to call some member functions from different classes which all have the same general syntax and base class. Something along the lines of
class A: public BaseClass
{
public:
A();
~A();
int DoFoo();
int DoBar();
int DoBarBar();
};
class B : public BaseClass
{
public:
B();
~B();
int DoSomething();
int DoSomethingElse();
int DoAnother();
};
Where I could potentially places the member functions from both classes into one map so that I could have something like
key value
"Option1" *DoFoo()
"Option2" *DoSomething()
"Option3" *DoFoo()
... ...
"Option6" *DoAnother()
Where I could call a function to return a value based on what option I chose, regardless of what class the function belongs to.
Through some searching, I tried to implement my own mapped set of functors. However, the map retains the address of the functor, but the functions within become null.
Here are my functor declarations which store a class object and a function pointer
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
//////////////////////////////////////////////////////////////
//Functor Classes
//////////////////////////////////////////////////////////////
class TFunctor
{
public:
virtual void operator()()=0; // call using operator
virtual int Call()=0; // call using function
};
// derived template class
template <class TClass> class TSpecificFunctor : public TFunctor
{
private:
int (TClass::*fpt)(); // pointer to member function
TClass* pt2Object; // pointer to object
public:
// constructor - takes pointer to an object and pointer to a member and stores
// them in two private variables
TSpecificFunctor(TClass* _pt2Object, int(TClass::*_fpt)())
{ pt2Object = _pt2Object; fpt=_fpt; };
// override operator "()"
virtual void operator()()
{ (*pt2Object.*fpt)();}; // execute member function
// override function "Call"
virtual int Call()
{return (*pt2Object.*fpt)();}; // execute member function
};
typedef std::map<std::string, TFunctor*> TestMap;
//////////////////////////////////////////////////////////////
//Test Classes
//////////////////////////////////////////////////////////////
//Base Test class
class base
{
public:
base(int length, int width){m_length = length; m_width = width;}
virtual ~base(){}
int area(){return m_length*m_width;}
int m_length;
int m_width;
};
//Inherited class which contains two functions I would like to point to
class inherit:public base
{
public:
inherit(int length, int width, int height);
~inherit();
int volume(){return base::area()*m_height;}
int area2(){return m_width*m_height;}
int m_height;
TestMap m_map;
};
where my inherit class constructor looks like:
inherit::inherit(int length, int width, int height):base(length, width)
{
m_height = height;
TSpecificFunctor<inherit> funcA(this, &inherit::volume);
m_map["a"] = &funcA;
TSpecificFunctor<inherit> funcB(this, &inherit::area2);
m_map["b"] = &funcB;
}
Which is where I am mapping two functions into a map. Things still look okay in the above function in terms of memory address and function pointers.
I then try to create an instance of inherit in a new class...
class overall
{
public:
overall();
~overall(){}
inherit *m_inherit;
TestMap m_mapOverall;
};
overall::overall()
{
m_inherit = new inherit(3,4,5);
TestMap tempMap = m_inherit->m_map;
int i = 0;
}
Here when I look at the values of m_inherit->m_map, I notice that the keys are still consistent, however the memory addresses of the functions which I tried to point to have disappeared.
I haven't had much experience with functors but from my understanding, it is able to retain states, which I assume means that I can call member functions outside of its class. But I'm starting to think that my member functions disappear because it is out of scope.
You are right, it is a scooping issue. In the inherit constructor, funcA and funcB are both allocated on the stack and destroyed once the function goes out of scope. The leaves m_map with stale pointers.
What you really want is something like
inherit::inherit(int lenght, int width, int height) :base(length, width)
{
m_height = height;
// allocated on the heap
TSpecificFunctor<inherit> * funcA = new TSpecificFunctor<inherit>(this, &inherit::volume);
m_map["a"] = funcA;
// allocated on the heap
TSpecificFunctor<inherit> * funcB = new TSpecificFunctor<inherit>(this, &inherit::area2);
m_map["b"] = funcB;
} // when this function exits funcA and funcB are not destroyed
But, to avoid any memory leaks, the destructor for inherit will need to clean up the values
inherit::~inherit()
{
for(TestMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
delete it->second;
}
}
Using new and delete can easily lead to memory leaks. To prevent them, I would suggest looking into smart points like std::unique_ptr and std::shared_ptr. Also, functors are becoming obsolete with the introduction of lambdas in C++11. They are really neat and worth looking into if you are not familiar with them.
If your compiler supports them, to do this with lambdas
#include <functional>
// ...
typedef std::map<std::string, std::function<int(void)>> TestMap;
// ...
inherit::inherit(int length, int width, int height):base(length, width)
{
m_height = height;
m_map["a"] = [this]() -> int { return volume(); };
m_map["b"] = [this]() -> int { return area2(); };
// can be called like so
m_map["a"]();
m_map["b"]();
}
// No need to clean up in destructors
You're right - the TSpecificFunctors go out of scope at the end of inherit's constructor, so you shouldn't keep pointers to them.
If you can, prefer smart pointers, e.g.
#include <memory>
...
typedef std::map<std::string, std::shared_ptr<TFunctor>> TestMap;
...
inherit::inherit(int length, int width, int height):base(length, width)
{
m_height = height;
m_map["a"] = std::shared_ptr<TSpecificFunctor<inherit>>(
new TSpecificFunctor<inherit>(this, &inherit::volume));
m_map["b"] = std::shared_ptr<TSpecificFunctor<inherit>>(
new TSpecificFunctor<inherit>(this, &inherit::area2));
}
Your main concern then is to ensure that the functors in m_inherit->m_map are not invoked after m_inherit is destroyed or you will get undefined behaviour. In this case, you're safe since you leak m_inherit (it's never destroyed).

Creating array of different objects

I have this code, but I don't see where I went wrong here. It seem to compile OK but I cannot access Computer or Appliance functions. Can someone please help me understand how can I make an array that holds different objects on this code example I have here?
#include <iostream>
using namespace std;
class Technics
{
private:
int price, warranty;
static int objCount;
double pvn;
char *name, *manufacturer;
public:
Technics()
{
this->objCount++;
};
Technics(int price)
{
this->objCount++;
this->price = price;
}
~Technics(){
this->objCount = this->objCount - 2;
};
static int getObjCount()
{
return objCount;
}
void setPrice(int price)
{
this->price = price;
}
int getPrice()
{
return this->price;
}
void resetCount()
{
this->objCount = 0;
}
};
int Technics::objCount = 0;
class Computer : public Technics
{
private:
int cpu, ram, psu, hdd;
public:
Computer() {}
Computer(int price)
{
this->setPrice(price);
}
void setCpu(int cpu)
{
this->cpu = cpu;
}
int getCpu()
{
return this->cpu;
}
};
class Appliance : public Technics
{
private:
int height;
int width;
char* color;
char* type;
public:
Appliance(){}
Appliance(int height, int width)
{
this->height = height;
this->width = width;
}
void setWidth(int width)
{
this->width = width;
}
int getWidth()
{
return this->width;
}
};
void main()
{
//Creating array
Technics *_t[100];
// Adding some objects
_t[0] = new Computer();
_t[1] = new Computer();
_t[2] = new Appliance();
// I can access only properties of Technics, not Computer or Appliance
_t[0]->
int x;
cin >> x;
}
The line:
_t[0] = new Computer();
Creates a computer object and stores it as a Technics base pointer in the array (i.e. for all intents and purposes while in that array, it is a Technics object).
You need to cast back to the derived class to access members that are more derived than those in Technics:
static_cast<Computer*>(_t[0])->Your_Member();
Use dyncamic cast if you don't know which derived type it is - it will return the casted pointer on success and NULL on fail so it's kind of a type-check - it has big runtime overhead though, so try to avoid it :)
EDIT in response to your closing comment:
//Calculate the length of your dynamic array.
//Allocate the dynamic array as a pointer to a pointer to Technics - this is like
//Making an array of pointers each holding some Technics heirarchy object.
Technics** baselist = new Technics*[some_length];
//Populate them the same way as before:
baselist[0] = new Computer();
baselist[1] = new Appliance();
PS: you could also use std::vector which is dynamically changeable as opposed to just created at run time - it's the best option if your allowed to use it. It saves you making your own resizable array code. Google it ;)
That's because _t is a pointer to Technics not Computer or Appliance.
Give Technics an "object type" parameter e.g. an enum that is TechnicsType.Computer for Computer and TechnicsType.Applicance for Appliance, check that and cast to the appropriate type to get the class methods.
The solution is very very simple :)
The super-class must have the virtual functions of the subclasses declared in the class definition.
For example: if the super-class computer have a sub-class called laptop that have a function int getBatteryLife();, so the computer class must have the definition virtual int getBatteryLife() to be called in the vector of pointers of the type computer.
Because _t is a Technics pointer array and, there is not possible to access to derived classes attributes. Use a Visitor Pattern like this or downcast your pointer:
// visitor pattern
class Visitor
{
void accept(Appliance &ref) { // access Appliance attributes };
void accept(Computer & ref) { // access Computer attributes };
};
class Technics
{
....
virtual void visit(Visitor &) = 0;
};
class Appliance
{
....
virtual void visit(Visitor &v) { v.accept(*this); }
};
class Computer
{
....
virtual void visit(Visitor &v) { v.accept(*this); }
};
Yes, you can only access the properties of Technics, since your variable has type Technics. You have to cast it to your Computer or Appliance class in order to execute your additional methods.
You really have to think about your design here. Is it really appropiate? Why do you have all of the objects inside the same container? Especially if you have different methods to call..this doesn't make sense..
If you really want to call different methods, you probably have to use a switch statement to decide what type you have, then call the appropiate methods (I guess you want to iterate through the whole container, or else it doesn't make sense to have a big container with different objects).