H/W:C ++エラー「抽象基本クラスを初期化しようとしています」

StackAsLinkedListというクラスを初期化しようとしています。StackAsLinkedListは抽象クラスStackの派生クラスでなければなりません(ここで使用できるテストコード: http://www.brpreiss.com/books/opus4/ )。

しかし、main()でこのコードをインスタンス化しようとするとエラーが発生します:

StackAsLinkedList stack;

error C2259: 'StackAsLinkedList' : cannot instantiate abstract class

私はStackAsLinkedListがStackの派生クラスとして定義されていると考えているので、これについて混乱します。

#ifndef STACK_H
#define STACK_H

#include "object.h"
#include "linkList.h"
#include "container.h"

class Stack : public virtual Container
{
public:

    virtual Object& Top() const = 0;
    virtual void Push (Object&) = 0;
    virtual Object& Pop() = 0;
};

class StackAsLinkedList : public Stack
{
    LinkedList list;

    class Iter;

public:

    StackAsLinkedList() : list() {}
    ~StackAsLinkedList() { Purge(); }

    //
   //Push, Pop and Top
    //
    void Push(Object& object);
    Object& Pop();
    Object& Top() const;

    //
   //purge elements from, and accept elements onto, the list
    //
    void Purge();
    void Accept (Visitor&) const;

    friend class Iter;
};

class StackAsLinkedList::Iter : public Iterator
{
    StackAsLinkedList const& stack;
    ListElement const* position; public: Iter (StackAsLinkedList const& _stack) : stack(_stack) { Reset(); } // //determine whether iterator is pointing at null // bool IsDone() const { return position == 0; } // //overloaded dereference and increment operator // Object& operator*() const; void operator++() const; void Reset() { position = stack.list.Head(); } }; #endif 

実装:

#include "stack.h"

void StackAsLinkedList::Purge()
{
    if ( IsOwner() )
    {
        ListElement const* ptr;

        for(ptr = list.Head(); ptr != 0; ptr = ptr->Next() )
            delete ptr->Datum();

        list.Purge();
        count = 0;
    }
}

void StackAsLinkedList::Push(Object& object)
{
    list.Prepend(&object);
    ++count;
}

Object& StackAsLinkedList::Pop()
{
    if(count == 0)
        throw domain_error ("stack is empty");

    Object& result = *list.First();
    list.Extract(&result);
    --count;
    return result;
}

Object& StackAsLinkedList::Top() const
{
    if(count == 0)
        throw domain_error ("stack is empty");

    return *list.First();
}

void StackAsLinkedList::Accept(Visitor& visitor) const
{
    ListElement const* ptr; for(ptr = list.Head(); ptr != 0 && !visitor.IsDone(); ptr = ptr->Next()) visitor.Visit(*ptr->Datum()); } 

クラスContainer:

#ifndef CONTAINER_H
#define CONTAINER_H

#include "object.h"
#include "visitor.h"
#include "iterator.h"
#include "ownership.h"

class Container : public virtual Object, public virtual Ownership
{
protected:

    unsigned int count;
Container() : count(0) {}

public:

    virtual unsigned int Count() const { return count; }
    virtual bool IsEmpty() const { return Count() == 0; }
    virtual bool IsFull() const { return false; }
    //virtual HashValue Hash() const;
    virtual void Put (ostream&) const;
    virtual Iterator& NewIterator() const { return *new NullIterator (); }

    virtual void Purge() = 0;
    virtual void Accept (Visitor&) const = 0;
 };

 #endif

編集:それはコンパイラは、オブジェクトのCompareTo()メソッドは、派生クラスのいずれかで実装されていないと表示されます。ただし、この機能は「Wrapper」というObjectの派生クラスに実装されています。

#ifndef WRAPPER_H
#define WRAPPER_H

#include "object.h"


template 
class Wrapper : public Object
{
protected:

    T datum;
    int CompareTo (Object const&) const;

public:

    Wrapper ();
    Wrapper (T const&);
    Wrapper& operator = (T const&);
    operator T const&() const;
    //HashValue Hash() const;
    void Put (ostream&) const;
};

//
// typedefs for for Wrappers representing different primitive
// data types
//
typedef Wrapper  Int;
typedef Wrapper  Char;
typedef Wrapper  Double;
typedef Wrapper  String;

#include "wrapper.inc"

#endif

しかし、StackはWrapperから継承していないので、これはStackToに対して別のCompareToメソッドを実装する必要があることを意味していますか?元の著者がこれをどのようにして動作させたかはわかりません(頭を傷つける)。

0
コンテナの定義を表示する必要があります
追加された 著者 Puppy,
@アレクサンドル:私はこのクラス(データ構造)の前にSTLのコースを取った、と私は信じて、私は完全にSTLを使用することができれば(STLは許可されている)
追加された 著者 dtg,
@Alexandre:本当に?私はスタックの要素をポップした後、オブジェクト(またはオブジェクトへのポインタ)を取得したいと考えましたか?
追加された 著者 dtg,
@Ben Voigt私は通常あなたの提案を受け取りますが、この課題の表面的な目標は、実際にはもう機能しない古いコードを見て、何が間違っているのか把握して修正することです。問題がどこにあるのか分かりませんが、現在のデザインを完全に廃止することなく解決する方法についてはわかりません。
追加された 著者 dtg,
確かに。 CompareTo()はWrapper(Objectから継承しています)に実装されていますが、StackがWrapperから継承しているようには見えません... hmmm ...もう一度、これは主に他の人が書いたソースコードです。
追加された 著者 dtg,
@Ben Voigt: "Object"の問題です: 'int Object :: CompareTo(const Object&)const':抽象です
追加された 著者 dtg,
@Dylan:おそらく StackAsLinkedListStack を継承して Container を継承しますか?そして途中で、 StackAsLinkedList の意味を CompareTo が意味するものを定義しなければなりません。
追加された 著者 Ben Voigt,
@Dylan:なぜ失敗したのかを理解したので、良いコードの理解に移ることをお勧めします。このコードは明らかにテストされていないだけでなく、ひどいスタイルを示します。おそらく、それは複数の言語で同じデザインを使用しようとしており、C ++コードは実際にはC ++デザインではなくJavaバージョンの貧弱な翻訳です。
追加された 著者 Ben Voigt,
どのコンパイラを使用していますか? MSVC ++またはgccの新しいバージョンでは、 Object&Pop()override; を記述することができ、一致しない場合はコンパイラが通知します。コンパイラがそのエラーとともに吐き出すという警告も表示する必要があります。
追加された 著者 Ben Voigt,
@Alexandre:基本的な操作がよく理解された後に、STL実装のすべての細かい部分に移動するだけで、簡単なテンプレートスタッククラスを理解することから始めます。
追加された 著者 Ben Voigt,
@DeadMG:あなたはそれを答えにする必要があると思う、それはほとんど問題であることは確かだ。
追加された 著者 Ben Voigt,
@Alexandre:ポインタのコピーは非投げです。このコレクションはポインタ(ポリモーフィズムに必要)のみを保持し、要素のコピーは作成されません。デザイン決定の根拠を理解し、それが適用されない場合は、それを固定し、それを不可侵のルールにするよりも重要です。
追加された 著者 Ben Voigt,
@Dylan:あなたは大丈夫です、アレクサンドルが話しているのは、ポインタを格納するコレクションではなく、値を格納するコレクションだけです。あなたのコレクションはポインタを格納し、 Pop からのポインタを返すのは問題ありません。
追加された 著者 Ben Voigt,
実際に、 toppop に対して別々の操作を行うことは、同時収集では重大な間違いです。
追加された 著者 Ben Voigt,
@AlexandreC:参照はぶら下がりません。オブジェクトは動的に割り当てられ、そのアドレスが delete のオペランドとして使用されるまで存在し続けます。ポインタを使用する方がはるかに優れたスタイルであると同意しました。
追加された 著者 Ben Voigt,
Container の定義は何ですか?
追加された 著者 bdonlan,
@Ben Voigt、Dylan:標準ライブラリから std :: stack テンプレートを理解することは、ますます便利であります。慣習的にこのようなJavaのインスピレーションを受けたコードを修正することは、ヒッポに踊る方法を教えるようなものです。
追加された 著者 Alexandre C.,
@Ben Voigt: std :: stack (そしておそらくあなたが話していること)の唯一の微妙な点は、top + popとpopだけではない理由を理解することです。しかし、私はあなたのポイントを得る。 @Dylanも、 Pop メソッドを修正して void を返すべきです。
追加された 著者 Alexandre C.,
@Dylan:ポイントは、同じ関数内の要素をポップして返すことができないことです。何らかの理由でトップオブジェクトをコピーする(return文で)が失敗した場合(つまり、例外をスローする)、スタックはそのままにしておきます。したがって、上部要素を取得するための top と、上部要素を削除するための pop を指定します。これは std :: stack クラスの動作と、スタッククラスを実装しないようにするための私のペットの理由の1つです。
追加された 著者 Alexandre C.,
@BenVoigt私の悪い、私は Top が参照を返すという事実のみを考えました。この場合、 Pop からポインタを返す必要があります。そうしないと、リファレンスがぶら下がります。 (また、 std :: stack > はここで望ましいセマンティクスを提供します)。並行収集は、ワームの別のバッグです(私は自分自身を実装したい決してないでしょう)。
追加された 著者 Alexandre C.,

1 答え

あなたは今あなたがそれを修正しようとしていることを説明したので、私は示唆している:

  • First step is to get it compiling, which you can do by adding a CompareTo(Object&) const member to StackAsLinkedList. You can use either dynamic_cast or the Visitor machinery to find out whether the object compared to is another collection.

  • Next, get rid of reference parameters in any case where the object will be stored by the callee and used after the function returns. And eradicate reference return types, where ownership is being transferred. You can either use pointers, or change the collection to pass-by-value (but don't pass-by-value if the collection should be polymorphic). You'd get:

    class Stack : public virtual Container
    {
    public:
        virtual Object& Top() const = 0;//short-term access to object, no ownership transfer, reference is ok here.
        virtual void Push (Object*) = 0; //pointer kept, ownership transfer, use pointer
        virtual Object* Pop() = 0;      //ownership transfer (caller must delete), use pointer
    };
    
  • Then, you should do something about the brokenness in the Visitor implementation. Right now, Accept always calls Visit(Object&) regardless of the dynamic type. You'd need to call a virtual Accept function on each individual member, in order to let the Visitor perform correctly on polymorphic collections.

私たちは、この時点でデザインを廃止する方法を検討しています。

3
追加された