How to use dynamic_cast with an array of pointers to a subclass

114 views Asked by At

I have an array of pointers to object class e_t :

class e_t {...};

I wrote a template class :

template <class E = e_t>
class cursor_t 

     { cursor_t(e_t ** &_source, size_t _total);

       e_t ** &Source;
       size_t  Total;

       E **First();
       E **Last();
       E **Skip(E **, short);
     };

For every function, I will for(_x to this->_total) this->Source and stop at the first, last or skipped dynamic_cast<E *>(*(this->Source + _x))... Works fine and it correctly stop...

The problem comes as returning the result ! Why can't I use e_t ** as E ** (knowing E is always descending from e_t) ?

return dynamic_cast<E **>(this->Source + _x); always fails at compile time...

I am Using cbuilder 5

2

There are 2 answers

10
Remy Lebeau On BEST ANSWER

You have over-complicated your design with too many pointer indirections. You have an array of pointers, you should simplify your interface by having the methods return individual elements of the array, as the caller shouldn't need direct access to the array itself, eg:

template <class E = e_t>
class cursor_t 
{
    e_t ** Source;
    size_t Total, Current;

public:
    cursor_t(e_t ** _source, size_t _total);

    E* First();
    E* Last();
    E* Previous();
    E* Next();
    E* Skip(short count);
};

template <class E>
cursor_t<E>::cursor_t(e_t ** _source, size_t _total) :
    Source(_source),
    Total(_total),
    Current(-1)
{
}

template <class E>
E* cursor_t<E>::First()
{
    for(size_t x = 0; x < Total; ++x) {
        E *e = dynamic_cast<E*>(Source[x]);
        if (e) { Current = x; return e; }
    }
    return nullptr;
}

template <class E>
E* cursor_t<E>::Last()
{
    for(size_t x = Total; x-- > 0; )
    {
        E *e = dynamic_cast<E*>(Source[x]);
        if (e) { Current = x; return e; }
    }
    return nullptr;
}

template <class E>
E* cursor_t<E>::Previous()
{
    if (Current < Total)
    {
        for (size_t x = Current; x-- > 0; )
        {
            E *e = dynamic_cast<E*>(Source[x]);
            if (e) { Current = x; return e; }
        }
    }
    return nullptr;
}

template <class E>
E* cursor_t<E>::Next()
{
    for (size_t x = Current + 1; x < Total; ++x)
    {
        E *e = dynamic_cast<E*>(Source[x]);
        if (e) { Current = x; return e; }
    }
    return nullptr;
}

template <class E>
E* cursor_t<E>::Skip(short count)
{
    E *e;
    if (count > 0) {
        while ((e = Next()) != nullptr && --count >= 0);
    }
    else if (count < 0) {
        while ((e = Previous()) != nullptr && ++count <= 0);
    }
    else if (Current < Total) {
        e = static_cast<E*>(Source[Current]);
    } else {
        e = nullptr;
    }
    return e;
}

Alternatively:

template <class E = e_t>
class cursor_t 
{
    e_t **Source, **End, **Current;

public:
    cursor_t(e_t ** _source, size_t _total);

    E* First();
    E* Last();
    E* Previous();
    E* Next();
    E* Skip(short count);
};

template <class E>
cursor_t<E>::cursor_t(e_t ** _source, size_t _total) :
    Source(_source),
    End(_source + _total),
    Current(nullptr)
{
}

template <class E>
E* cursor_t<E>::First()
{
    for(e_t *t = Source; t < End; ++t) {
        E *e = dynamic_cast<E*>(t);
        if (e) { Current = t; return e; }
    }
    return nullptr;
}

template <class E>
E* cursor_t<E>::Last()
{
    for(e_t *t = End; t > Source; )
    {
        E *e = dynamic_cast<E*>(--t);
        if (e) { Current = t; return e; }
    }
    return nullptr;
}

template <class E>
E* cursor_t<E>::Previous()
{
    if (Current)
    {
        for (e_t *t = Current; t > Source; )
        {
            E *e = dynamic_cast<E*>(--t);
            if (e) { Current = t; return e; }
        }
    }
    return nullptr;
}

template <class E>
E* cursor_t<E>::Next()
{
    if (Current) 
    {
        for (e_t *t = Current + 1; t < End; ++t)
        {
            E *e = dynamic_cast<E*>(t);
            if (e) { Current = t; return e; }
        }
    }
    return nullptr;
}

template <class E>
E* cursor_t<E>::Skip(short count)
{
    E *e;
    if (count > 0) {
        while ((e = Next()) != nullptr && --count >= 0);
    }
    else if (count < 0) {
        while ((e = Previous()) != nullptr && ++count <= 0);
    }
    else {
        e = static_cast<E*>(Current);
    }
    return e;
}
4
blueperfect On

Thanks all folks !

I found...

I should use dynamic_cast for 1 pointer of the array, but I will use reinterpret_cast for the whole array...