Возможно ли для базового класса предоставить интерфейс итератора, который реализуют производные классы? - PullRequest
1 голос
/ 17 февраля 2012

Я портирую этот код из Visual C ++ 6.0 (он также работал со старым GCC ++) на Visual Studio 2010 C ++.Код компилируется, но выдает исключение.

У меня есть базовый класс, CncMatchedQueryAtom.Этот класс содержит совпадения различных типов целевых атомов (это приложение сопоставления графиков) для 99% случаев, когда между запросом и целью существует однозначное совпадение.Это обрабатывается производным классом CncMatchedQueryAtomSimple.Этот класс отлично работает.Проблема в том, что некоторые атомы запросов соответствуют группам атомов, это обрабатывается классом CncMatchedQueryAtomGroup.Этот класс содержит вектор с подобранными атомами.Я хочу, чтобы класс итератора, определенный в базовом классе, инкапсулировал векторный итератор в производный класс так, чтобы begin () возвращал вектор begin (), а end - конец вектора ().Старая версия имеет проблемы с end () во время выполнения, потому что она выполняет преобразование следующим образом:

return & * group.end ();

Что больше не разрешено в Visual C ++. Так какбазовый класс может указать итератор, который могут реализовать производные классы?Это не кажется мне очевидным, но я новичок в C ++.И не то, что опытные разработчики C ++, с которыми я работаю, тоже знают.

По сути, я хочу, чтобы в базовом классе были методы, обеспечивающие функции начала и конца, которые реализуют производные классы.

Вот код:

 class CncMatchedQueryAtom
{
protected:
int notBlockAllocated;
public:
int allocateIndividually() const
{
    return notBlockAllocated;
}
const CncAtom *queryAtom;

CncAtom *queryAtomVolitile() const
{
    return (CncAtom*)queryAtom;
}

// set when the class has been allocated by newing

// intialize all default constructors to be notBlockAllocated
CncMatchedQueryAtom()
    : notBlockAllocated(1)
    , queryAtom(NULL) // i don't think this needs to be initialized to null
{
}

CncMatchedQueryAtom(int noBlock)
    : notBlockAllocated(noBlock)
    , queryAtom(NULL) // i don't think this needs to be initialized to null
{
}

// may not need this now that it's a virtual!
CncMatchedQueryAtom(const CncMatchedQueryAtom &that)
    : queryAtom(NULL)
{
    *this = that;
}

// this needs to be virtual so when delete CncMatchedQueryAtom is called
// the virtual calss members are destructed too
virtual ~CncMatchedQueryAtom()
{
}

virtual void dump() const =0;
virtual void clearMapping() =0;
virtual CncMatchedQueryAtom *newCopy() const =0;
virtual void coverHits(class CncTarget *) const = 0;
// iterates over all matched target atoms for this query atom
class iterator  
{
private:
    CncMatchedTargetAtom *ptr;

public:

    iterator()
    {
    }
    iterator(const CncMatchedTargetAtom *targetAtom)  // constructor from a   target ptr
        :ptr((CncMatchedTargetAtom *)targetAtom)
    {
    }
    iterator(const iterator &oldOne)
        :ptr(oldOne.ptr)
    {
    }
    ~iterator()
    {
    }

    int operator==(const iterator &that) const
    {
        return ptr==that.ptr;
    }
    int operator!=(const iterator &that) const
    {
        return ptr!=that.ptr;
    }

    const CncMatchedTargetAtom &operator*() const
    {
        return *ptr;
    }

    iterator operator++(int NotUsed)  // post increment
    {
        iterator returnValue(*this);
        ++ptr;
        return returnValue;
    }
    iterator &operator++()  // pre increment
    {
        ++ptr;
        return *this;
    }

    int operator<(const iterator &rhs) const
    {
        return (this->ptr < rhs.ptr);
    }


    CncMatchedTargetAtom *operator->()
    {
        return ptr;
    }
};

virtual iterator begin() const =0;
virtual iterator end() const =0;
virtual int size() const = 0;
virtual double molecularWeight() const = 0;

const CncAtom *getFirstTargetAtom() const
{
    return (*begin()).matchedTargetAtom;
}
CncAtom *getFirstTargetAtomVolitile() const
{
    return (CncAtom*)getFirstTargetAtom();
}

}; // class CncMatchedQueryAtom
class CncMatchedQueryAtomSimple : public CncMatchedQueryAtom
{
public:
// we need a constructor here since this is allocated with blockAlloc
CncMatchedQueryAtomSimple()
    : CncMatchedQueryAtom(0)
{
}

// we use simple.targetAtom as a temporary variable
// used to pass to matching functions
CncMatchedTargetAtom simple;

void clearIt()
{
    queryAtom=NULL;
    notBlockAllocated=0;
}

// if queryAtom is an element-type atom (or Lp or A atom)
void dump() const;
void clearMapping()
{
}
CncMatchedQueryAtom *newCopy() const
{
    // since this is usually not allocatedIndividually I'll set
    // the notBlockAllocatedFlag on the copy to be sure if this
    // does happen it will individually deallocate it
    CncMatchedQueryAtomSimple *retVal = new CncMatchedQueryAtomSimple(*this);
    retVal->notBlockAllocated = 1;
    return (CncMatchedQueryAtom *)retVal;
}

void coverHits(class CncTarget *) const;

iterator begin() const
{
    return &simple;
}

iterator end()  const
{
    return &simple+1;
}

int size() const
{
    return 1;
}

double molecularWeight() const
{
    return CncMolGetAtomicMassAve(simple.matchedTargetAtom->getAtomicNumber());
}
}; // class CncMatchedQueryAtomSimple
class CncMatchedQueryAtomGroup : public CncMatchedQueryAtom
{
public:

// if queryAtom is an R- or X-group searching for 
std::vector<CncMatchedTargetAtom> group;

void dump() const;

void clearMapping()
{
    group.clear();
}
CncMatchedQueryAtom *newCopy() const
{
    return new CncMatchedQueryAtomGroup(*this);
}

void coverHits(class CncTarget *) const;

iterator begin() const
{
    return &*group.begin();
}

iterator end() const
{
            // this is a hack, works with Visual C++ 6.0 and older GCC++ but not VS C++ 2010
    return &*group.end(); // Throws error at runtime!   Iterator Not Dereferencable
}

int size() const
{
    return group.size();
}

double molecularWeight() const
{
    double sum=0;
    std::vector<CncMatchedTargetAtom>::const_iterator q;
    for (q=group.begin()
        ; q!=group.end()
        ; ++q)
    {
        sum += CncMolGetAtomicMassAve(q->matchedTargetAtom->getAtomicNumber());
    }
    return sum;
}

}; // class CncMatchedQueryAtom

Пример того, как называется итератор:

// Sample call to the iterator
// (*elem)->getMatchedAtom() returns a CncMatchedQueryAtom *

CncMatchedQueryAtom::iterator atomMatched;

// welp it looks like we have to do these
//(*elem)->getFirstTargetAtom
for (atomMatched=(*elem)->getMatchedAtom()->begin()
     ; atomMatched!=(*elem)->getMatchedAtom()->end()  // Runtime exception here!
     ; ++atomMatched)
{
existenceFingerprint.setBit(
        atomMatched->matchedTargetAtom->indexInStructure);
}

Спасибо, надеюсь, это не слишком много кода ...

1 Ответ

4 голосов
/ 17 февраля 2012

Нельзя преобразовать итераторы из одного контейнера в итераторы в другой контейнер.

Раньше он работал с VC6, потому что они использовали указатель как vector::iterator. Более поздние версии имеют класс итератора, где преобразование не работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...