I am creating a simple test entity-component system. I have a base Component class with several derived classes. I then have several systems that apply some logic to these components.
// Component.h
// ------------
class Component
{
public:
Component();
~Component();
}
// ControlComponent.h
// -------------------
#include <string>
#include "Component.h"
class ControlComponent : public Component
{
public:
std::string input = ""; // store simple input instruction
ControlComponent();
~ControlComponent();
};
// ControlSystem.cpp
void ControlSystem::update(Entity* entity)
{
vector<Component*>* components = entity->getComponents();
for (Component* component : *components)
{
PositionComponent* pc = static_cast<PositionComponent*>(component);
ControlComponent* cc = static_cast<ControlComponent*>(component);
if (pc != nullptr && cc != nullptr)
{
std::cout << "Which direction would you like to go?" << std::endl;
std::string input;
std::cin >> input;
cc->input = input; // application breaks here
// Apply some logic...
}
}
}
When I static_cast from base Component* to either of the derived components (PositionComponent* or ControlComponent*) and when both results are not nullptr(i.e the cast was successful), I get invalid values, like cc->input not being able to read characters from string etc.
I wire up the components in my entity factory, like this:
void EntityFactory::wireUpPlayer(Entity* player)
{
player->addComponent(new HealthComponent());
player->addComponent(new ControlComponent());
player->addComponent(new PositionComponent());
}
And the implementation for addComponent is as follows:
void Entity::addComponent(Component* component)
{
m_components.push_back(component);
}
These components are shown to have valid memory addresses, so I'm not sure where the issue is coming from.
static_cast does not check validity at runtime; if the cast compiled, it assumes at runtime that the conversion is okay. If you aren't casting a null pointer, the result of a static_cast will not be a null pointer. To get a checked cast you need dynamic_cast and that, in turn, requires the pointer being converted to point to a polymorphic type, i.e., one that has at least one virtual function. That means changing Component to have at least one virtual function.
When I static_cast from base Component* to either of the derived components (PositionComponent* or ControlComponent*) and when both results are not nullptr(i.e the cast was successful)...
When casting from a base class to a derived class, static_cast is telling the compiler, "Trust me, I know what I'm doing." In other words, if it's even potentially legal, it will "succeed" and return non-nullptr. If, at runtime, it's not legal, you'll get undefined behavior, from trying to use an instance of one class as if it were of another class.
Use dynamic_cast instead.
As Pete Becker and Josh Kelley said, use dynamic_cast and I believe you also need to set at least one function as virtual. If you do not, the compiler will not record the inheritance and dynamic_cast will likely still return nullptr. When performing inheritance, I suggest making the class destructors virtual. This is also good practice when unmanaged resources need to be disposed of in the destructor of a derived class and you only have a pointer to the base class, the derived class destructor will only be called so long as the destructors are virtual. There was a post that explained it here: When to use virtual destructors?
Related
I am experimenting a little bit with inheritance in C++ and I stepped on a case that I don't quite understand. When I try to compile the code I get:
error: cannot ‘dynamic_cast’ ‘base’ (of type ‘class Base*’) to type
‘class SomeInterface*’ (source type is not polymorphic)
I assume that it is not a proper way of casting, because SomeInterface is not related to Base, but is there a way to make it work? Maybe there something I can add to the class to make static_cast possible? Or is it just a bad architecture and I should rearrange my code to not introduce cases like this one? I'd appreciate any comments or resources I could read to understand this behaviour and possibly learn how to make it work.
class Base
{
};
class SomeInterface
{
public:
void call_me() { }
};
class Derived : public Base, public SomeInterface
{
};
void try_call_me(Base* base)
{
// line below causes an error
SomeInterface* some_interface_instance = dynamic_cast<SomeInterface*>(base);
some_interface_instance->call_me();
}
int main()
{
Derived derived_instance;
Base* base_instance = &derived_instance;
try_call_me(base_instance);
return 0;
}
dynamic_cast requires (except for up-casts) that the base class type used in the argument is polymorphic.
A class in C++ is called polymorphic if it has at least one virtual function. So you need to add one to your Base, for example the destructor:
struct Base
{
virtual ~Base() = default;
};
Polymorphic classes store additional information that is required for dynamic_cast to work at runtime.
However, that is a costly operation to do. Reconsider why try_call_me is expecting a pointer to Base instead of SomeInterface if that is really what it needs.
If you keep it as it is, you also need to add error checking to the dynamic_cast. It will return a null pointer if base doesn't refer to an object whose most-derived object contain a SomeInterface base class subobject that could be side-casted to:
SomeInterface* some_interface_instance = dynamic_cast<SomeInterface*>(base);
if(!some_interface_instance) {
// didn't pass a suitable pointer, error!
// fail here, otherwise there will be undefined behavior!
} else {
some_interface_instance->call_me();
}
(If you use references instead of pointers, dynamic_cast will throw an exception instead of producing a null pointer value.)
I have a cpp code where in class c is derived from class b and class b is derived from class a.
Now class b has some public data member. So I am creating a instance of class c on heap passing its pointer to another class as pointer to a and there it is downcasting that pointer to pointer of class b and then printing public variables of class b.
Is this a valid downcasting. I am asking because just change of compiler has broken this working code.
I am including below code snippet which captures problem I am having.
#include <iostream>
using namespace std;
class grand
{
};
class parent : public grand
{
public : parent(){i=0;}
int i;
parent(int j){ i = j;}
void set(int j){i = j;}
};
class child : public parent{
public: child(){};
};
void print ( grand* ptr)
{
parent *p = (parent*) ptr;
std::cout << std::endl << p->i << std::endl;
}
int main() {
// your code goes here
child c;
c.set(9);
print(&c);
return 0;
}
Thanks
Is this a valid downcasting.
Yes. Your cast internally applies static_cast, which, according to §5.2.9/11, will give you the right result. If the argument for ptr doesn't point to a parent, the result of the cast is undefined - and so would the execution of the following code be.
Downcasting of polymorphic types in C++ works via dynamic_cast. Your grand class above isn't polymorphic - you have to add at least a virtual destructor to grand to make it polymorphic. Otherwise you'll get a compiler error with the following code.
parent *p = dynamic_cast<parent*>(ptr); // Once grand is polymorphic...
And check whether the result, p, is non-zero. Only this method reveals (at runtime) whether the cast worked! All others either invoke undefined behavior or undefined, non-zero values.
Some notes:
Downcasting is almost always a sign of bad design. Avoid it if possible, using - for example - virtual (print) functions.
print should take a pointer to const since it doesn't modify any data members.
Your code, as written, is in fact valid, but there are a bunch of observations I'd like to make. Note that it's valid only because the object you pass to print is a parent or further derived class.
Then note that since you have to cast it the print function it's much safer to just change the function signature to take aparent instead of a grand and then you don't have to worry about the casting.
Then note that a likely cause of your problem is that in the file that does the cast, the compiler doesn't see the relationship between grand and parent so your C-style cast falls back to reinterpret_cast which is not what you want. If you can't change the signature of print at least change the cast to static_cast (or possibly dynamic_cast, but you can't do that in your example because the classes aren't polymorphic) so that the compiler will fail to compile when it can't see the class relationship.
Instead of a C-style cast you should apply a dynamic_cast or a at least a static_cast if you compile without RTTI (runtime type information) for some reason.
Your C-style cast is the same as a reinterpret_cast, which essentially interprets the memory pointed to as if an object of type parent would have been constructed there. But, every compiler may have a different memory layout of derived classes, thus that may work in some circumstances but there's no guarantee.
Let's say I have class SuperClass { public: int a; } and class SubClass : SuperClass { public: int b; } and I took a pointer to an instance of the SubClass SubClass *subPointer and addressed that pointer to a SuperClass pointer SuperClass *superPointer = subPointer. Now of course I can always cast the superPointer object to a pointer of SubClass because the only thing it stores is an adress. But how would I know if the object superPointer is pointing to an instance of SubClass or is just a SuperClass pointer?
You usually don't want to use typeid for this.
You usually want to use dynamic_cast instead:
if (SubClass *p = dynamic_cast<SubClass *>(SuperClassPtr))
// If we get here (the `if` succeeds) it was pointing to an object of
// the derived class and `p` is now pointing at that derived object.
A couple of notes though. First of all, you need at least one virtual function in the base class for this to work (but if it doesn't have a virtual function, why are you inheriting from it?)
Second, wanting this very often tends to indicate design problems with the code. In most cases, you want to define a virtual function in the base class, which you (if necessary) override in the derived class to do whatever's needed so you can just use a pointer to the base class throughout.
Finally, as it stands right now, most of the conversions will fail -- you've used the default (private) inheritance, which prevents the implicit conversion from derived * to base * that you'd normally expect to see happen (you probably want class SubClass : public SuperClass).
Use RTTI machanism. Like:
if(typeid(*superPointer) == typeid(SuperClass)) superPointer->dosomething();
if(typeid(*superPointer) == typeid(SubClass)) superPointer->dosomethingelse();
I tried this which didn't work:
void Map::OnLMClick(short xPos, short yPos)
{
SObject* pSObject = pEditWindow->GetSelectedItem();
if (pSObject==SOTile)
{
/* Do */
I tried this as a test:
SObject* EditorWindow::GetSelectedItem()
{
return pSOTile[1]; //pSOTile[1] is a valid pointer, member of EditorWindow
}
SOTile class is a child of base class SObject. So, is it possible to create a Base* to get one of its child's* returned and then have the program react differently depending of what child it returned? If it is the case, how do I then have access to members of it's child that are not members of base?
If your types are polymorphic (i.e. if they have at least one virtual function), you can use dynamic_cast:
Base* pObject = get_object(); // May return a pointer to Derived
Derived* pDerived = dynamic_cast<Derived*>(pObject);
Notice, that dynamic downcasts are sometimes an indicator of bad design. Try to think if a better arrangement of virtual functions in your hierarchy would help.
Without knowing the concrete application domain, it is not possible for me to give more concrete advices.
dynamic_cast operator performs a special checking when a class is polymorhic.
SOTile* pSOTile = dynamic_cast<SOTile*>(pSObject);
if (pSOTile)
{
/* Do */
}
Since SOTile is a pointer to a type that derives from SObject, you should not need to cast at all, since the compiler should be able to automatically resolve an SObject pointer from the derived pointer and then compare the two SObject pointers together (the same way that you can assign a derived pointer to a base pointer without type-casting). Some compilers, like Borland's, support that just fine, eg:
class Base
{
};
class Derived : public Base
{
};
Derived *d = ...;
Base *b = ...;
if (b == d) // <-- compiles fine
However, if for whatever reason your compiler does not allow that, you can manually cast the derived pointer using static_cast (don't use dynamic_cast to cast the base pointer):
if (pSObject == static_cast<SObject*>(SOTile))
If SOTile is not a pointer to a type that derives from SObject, static_cast will fail at compile-time.
I wouldn't recommend to use dynamic_cast. Instead, you can implement that different behavior in different child class. Sometimes called as "template method" pattern
Here to show you what I mean exactly it hard to describe without code:
class Object
{
// attributes..
};
class Attribute
{
public:
void myfunc();
};
class Character: public Object, public Attribute
{
};
void main()
{
Object* ch = new Character;
// How can I call the myfunc() from Attribute
// tried static_cast<Attribute*>(ch);
}
I only just have a Object Class pointer and i doesn't know
if it is a Character Object or another object which inherit from the
Attribute class, what i know is that the class inherit from Attribute Class.
Cross casting can only be done by dynamic_cast.
Object * o = new Character;
Attribute * a = dynamic_cast<Attribute*>(o);
if (!a) throw_a_fit();
a->myfunc();
However, for this to work you must have polymorphic base classes (they must have at least one virtual function).
If you know that you have an object of the correct type, you can cast explicitly:
Object * ch = /* something that's a Character */
static_cast<Attribute *>(static_cast<Character *>(ch))->myfunc();
Obviously this will not be correct if the type of the most-derived object pointed to by ch is not a subtype of Attribute.
If your class hierarchy is polymorphic (i.e. has at least one virtual function in each base class that you care about), then you can use dynamic_cast directly at runtime and check if it succeeded, but that is a comparatively expensive operation. By contrast, the static cast does not incur any runtime cost at all.