基类是否可以提供派生类实现的迭代器接口?

时间:2012-02-17 17:19:19

标签: c++ iterator

我将此代码从Visual C ++ 6.0(它也使用较旧的GCC ++)移植到Visual Studio 2010 C ++。代码编译但抛出异常。

我有一个基类CncMatchedQueryAtom。此类用于包含不同类型的目标原子的匹配(这是一个图形匹配应用程序),99%的情况下查询和目标之间存在一对一匹配。这由派生类CncMatchedQueryAtomSimple处理。这堂课很棒。问题是一些查询原子匹配原子组,这是由类CncMatchedQueryAtomGroup处理的。该类包含具有匹配原子的向量。我希望在基类中定义的iterator类将向量迭代器封装在派生类中,这样begin()返回向量begin(),end返回向量的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 个答案:

答案 0 :(得分:4)

您无法将迭代器从一个容器转换为迭代器到另一个容器。

它曾经与VC6一起使用,因为它们碰巧使用指针vector::iterator。更高版本有一个迭代器类,转换不起作用。