I've been struggling with with this C++ thing for a while. I've created base object class and derived object class and I'm trying to store references to both base and derived objects in a vector of base-class pointers (avoid object slicing). With pointer, I am able to run virtual methods and I can confirm that pointer points to derived-class object, however I cannot get to derived class specific variables. Is there any way of doing it?
Base class object:
class Base
{
public:
Manager* manager;
Base(){}
Base(Manager* mManager){
manager = mManager;
}
virtual void init(){}
virtual void speak() {
std::cout << "Base class is speaking!" << std::endl;
}
};
Derived class object:
class Derived : public Base
{
public:
Manager* manager;
int DerviedVariable = 100;
Derived(){}
Derived(Manager* mManager){
manager = mManager;
}
void speak() override {
std::cout << "Derived class is speaking!" << std::endl;
}
};
Those objects (Base na Derived) are created and stored using Manager class and array called groupedEntities:
constexpr std::size_t maxGroups = 32;
using Group = std::size_t;
class Manager
{
public:
std::array<std::vector<Base*>, maxGroups> groupedEntities;
void addToGroup(Base* mBase, Group mGroup)
{
groupedEntities[mGroup].emplace_back(mBase);
}
std::vector<Base*>& getGroup(Group mGroup)
{
return groupedEntities[mGroup];
}
template <typename T, typename... TArgs>
T* addEnt(TArgs&&... mArgs)
{
T* e(new T(this));
return e;
}
};
I am create objects and try to reference them like that:
void main() {
std:size_t groupBlob = 0u;
Manager* manager = new Manager();
Derived* blob1(manager->addEnt<Derived>());
Derived* blob2(manager->addEnt<Derived>());
manager->addToGroup(blob1, groupBlob);
manager->addToGroup(blob2, groupBlob);
auto& grouped(manager->getGroup(groupBlob));
for (auto& e : grouped)
{
e->speak();
std::cout << e.DerviedVariable ;
}
}
Unfortunately, e.DerviedVariable is inaccessible, whereas speak() function says "Dervied class is speaking". Is there any way to access Derived-class variables with this architecture? Thanks
Yes it is possible. You only need to cast the pointer. The simplest syntax is:
((Derived*)e)->DerviedVariable
which is equivalent (modulo casting away constness, if any) to C++ish
static_cast<Derived*>(e)->DerviedVariable
The word “static” here reminds that there is no runtime checking: the compiler trusts you that e
indeed points to an instance of Derived
. If it doesn't, undefined behavior occurs. The safer alternative is dynamic_cast
:
Derived *ee = dynamic_cast<Derived*>(e);
if (ee)
x = ee->DerviedVariable;
It returns NULL if the object is not an instance of Derived
. (Note that references can be casted as well, but as there is no NULL reference, dynamic_cast
will throw instead if cast is not possible)
Nevertheless, using such casts is often considered a bad practice, for a reason. Virtual functions are preferable, mostly because using them don't require you to even know the actual object type at the call point.
You can use dynamic_cast in such cases. The expression dynamic_cast<Derived*>(e)
where e
is of type Base*
will evaluate to a Derived*
if e
does in fact point to an object of Derived
type, otherwise it will evaluate to a null pointer.
if(Derived* d = dynamic_cast<Derived*>(e)) {
std::cout << d->e.DerviedVariable;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.