2012-02-17 4 views
1

私はこのコードをVisual C++ 6.0から移植しています(以前のGCC++でも動作していました)からVisual Studio 2010 C++に移植しています。コードはコンパイルされますが、例外がスローされます。基本クラスは、派生クラスが実装するイテレータインターフェイスを提供できますか?

私は基本クラスCncMatchedQueryAtomを持っています。このクラスは、異なる種類のターゲットアトム(これはグラフマッチングアプリケーションです)のマッチを含む場合に使用され、99%の場合、クエリとターゲットの間に1対1のマッチがあります。これは、派生クラスCncMatchedQueryAtomSimpleによって処理されます。このクラスは素晴らしいです。問題は、いくつかのクエリーアトムがアトムのグループとマッチすることです。これは、クラスCncMatchedQueryAtomGroupによって処理されます。このクラスには、一致する原子を含むベクトルが含まれます。 begin()がベクトルbegin()を返し、endがベクトルのend()を返すように、ベースクラス内で定義されたイテレータクラスで派生クラスのベクトルイテレータをカプセル化します。 古いバージョンでは、実行時にend()に問題があります。これは、変換によって次のように変換されるためです。

return & * group.end();

Visual C++でもう許可されていない 基本クラスは、派生クラスで実装できるイテレータをどのように指定できますか?これは私にはあまり明白ではないようですが、私はC++を初めて使っています。 C++開発者が私の仕事を経験していることは、どちらにも分かっていません。

基本的には、派生クラスが実装するbegin関数とend関数を提供するメソッドを基本クラスに追加します。

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

おかげで、うまくいけば、これはあまりにも多くのコードではありませんあなたは...

答えて

4

ここ

はコードがありますあるコンテナのイテレータをイテレータに変換することはできません。

これは、VC16を使用していました。なぜなら、ポインタがvector::iteratorというように使用されていたからです。それ以降のバージョンでは、変換が機能しないイテレータクラスがあります。

+0

もう一度言い換えると、法的コードではありませんでしたが、VC6でも動作することは決してありませんでした。 – ildjarn

+0

右のポインタは、 'vector :: iterator'のための有効な選択肢である一種のランダムアクセスイテレータです。ポインタに別のコンテナへのポインタを割り当てることができるのは、イテレータ契約の一部ではありません。それはちょうどVC6のために偶然によって働いた。 –

+0

このコードもgccで動作しました。ベースクラスが実際のイテレータをプロキシするイテレータ "インタフェース"を提供する場合、私は何をしたいのですか?これはC++では不可能ですか?オブジェクトの目的を破るのは一種です。 – whomer

関連する問題