0
votes

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

2
Unrelated: main() must be declared to return int. - Ted Lyngmo
Add a pure virtual function virtual int getDerviedVariable() = 0; to Base and implement it in Derived - Richard Critten
If you think you need to get to derived-class-specific variables from a base class pointer, your design almost certainly needs work. Typically, either the base class should provide a virtual function for the job, or your pointers should be to the derived class, not the base. Think about what makes sense given what your classes are supposed to represent. - JaMiT

2 Answers

1
votes

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.

0
votes

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;
}