简体   繁体   中英

Vector of pointers to base class containing base and derived class objects - accessing derived-class specific variables

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM