H/W: C ++ Hatası "Soyut temel sınıfını başlatmaya çalışıyor"

StackAsLinkedList adlı bir sınıfı başlatmaya çalışıyorum. Bu, soyut sınıf Stack'ın türetilmiş bir sınıfı olmalıdır (burada bulunan test kodu: http://www.brpreiss.com/books/opus4/ ).

Ancak, bu kodu ana (): olarak başlatmaya çalışırken bir hata alıyorum:

StackAsLinkedList stack;

error C2259: 'StackAsLinkedList' : cannot instantiate abstract class

Bunun hakkında kafam karıştı, çünkü StackAsLinkedList'in Stack'ın türetilmiş bir sınıfı olarak tanımlandığını düşündüm:

#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 

Hayata geçirme:

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

sınıf Konteyner:

#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

DÜZENLEME: Derleyici, Object'te CompareTo() yönteminin türetilmiş sınıfların hiçbirinde uygulanmadığını söyler. Ancak, bu işlev "Wrapper" adlı Object'in türetilmiş sınıfında uygulanır:

#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

Ancak Stack, Wrapper'dan miras almaz - bu yüzden başka bir CompareTo yönteminin Stack için uygulanması gerektiği anlamına mı geliyor? Orijinal yazarın bunu nasıl çalıştırdığından emin değil (çizikler kafa).

0
Kapsayıcı tanımını göstermeniz gerekiyor
katma yazar Puppy, kaynak
@Alexandre: STL'de bu dersten önce bir ders aldım (Veri Yapıları) ve inanıyorum ki, eğer STL'yi kullanabilirsem (STL'ye izin yok)
katma yazar dtg, kaynak
@Alexandre: Gerçekten mi? Nesneyi geri almak istediğiniz (veya nesneye bir işaretçi) yığının bir elemanını patlattıktan sonra düşündüm mü?
katma yazar dtg, kaynak
@Ben Voigt Normalde önerinizi alırdım, ancak bu ödevin görünürlüğü, artık gerçekten işe yaramayan eski kodlara bakmak ve onun neyin yanlış olduğunu anlamak (ve düzeltmek). Problemin nerede olduğunu belirledikten sonra, mevcut tasarımın tamamen kaldırılmadan nasıl çözüleceğinden emin değil!
katma yazar dtg, kaynak
Aslında. CompareTo() Wrapper'da (Object'ten miras alınır) uygulanır, fakat Stack'in Wrapper'dan miras kaldığı görünmüyor ... hmmm ... yine bu bir başkasının yazdığı büyük ölçüde kaynak kodudur - bunu anlamaya çalışıyorum.
katma yazar dtg, kaynak
@Ben Voigt: "Object" ile ilgili bir problem ortaya çıkıyor: 'int Object :: CompareTo (const Object &) const': abstract
katma yazar dtg, kaynak
@Dylan: Muhtemelen StackAsLinkedList Yığını devralır Container devralır Object ? Daha sonra yol boyunca, StackAsLinkedList için CompareTo anlamına ne gerektiğini tanımlamanız gerekir.
katma yazar Ben Voigt, kaynak
@Dylan: Artık neden başarısız olduğunu anladığına göre, iyi bir kodun anlaşılmasına geçmenizi öneririm. Bu kod açık bir şekilde test edilmediği gibi, korkunç bir tarz sergiler. Muhtemelen aynı tasarımı birden çok dilde kullanmaya çalıştığı ve C ++ kodunun aslında bir C ++ tasarımı değil, Java sürümünün zayıf bir çevirisi olduğu için.
katma yazar Ben Voigt, kaynak
Hangi derleyiciyi kullanıyorsunuz? MSVC ++ veya gcc'nin daha yeni bir sürümü ile Object & Pop() geçersiz kılma; yazabilirsiniz ve derleyici, eşleşmediğini size bildirir. Ayrıca, derleyicinin bu hatayla birlikte tükürdüğü uyarılarını da göstermeniz gerekir.
katma yazar Ben Voigt, kaynak
@Alexandre: Muhtemelen basit şablonlu bir yığın sınıfını anlamaya başlayacağım ve temel işlemler iyi anlaşıldıktan sonra sadece STL uygulamasının tüm inceliklerini ele alacağım.
katma yazar Ben Voigt, kaynak
@DeadMG: Bence bunu bir cevap vermeniz gerekiyor, sorun olmak neredeyse kesin.
katma yazar Ben Voigt, kaynak
@Alexandre: Bir işaretçiyi kopyalamak atılmıyor. Bu koleksiyon sadece işaretçileri tutar (polimorfizm için gerekli), hiçbir eleman kopyası yapılmaz. Bir tasarım kararının gerekçesini ve uygulanamadığı halleri anlamak, onu sabitlemekten ve onu dokunulmaz bir kural haline getirmekten daha önemlidir.
katma yazar Ben Voigt, kaynak
@Dylan: Sen iyisin, Alexandre'in bahsettiği şey sadece değerleri saklayan koleksiyonları değil, işaretçileri depolayan koleksiyonları ifade eder. Koleksiyonunuz işaretçileri depolar ve işaretçiyi Pop öğesinden geri döndürür.
katma yazar Ben Voigt, kaynak
Aslında, eş zamanlı koleksiyonlar söz konusu olduğunda top ve pop için ayrı işlemlerin yapılması ciddi bir hatadır.
katma yazar Ben Voigt, kaynak
@AlexandreC: Referans sarkmıyor, nesne dinamik olarak tahsis edildi ve adresi delete işleneni olarak kullanılıncaya kadar var olmaya devam edecek. İşaretçiyi kullanmanın çok daha iyi bir tarz olduğu kabul edildi.
katma yazar Ben Voigt, kaynak
Container 'ın tanımı nedir?
katma yazar bdonlan, kaynak
@Ben Voigt, Dylan: Daha iyisi ve daha kullanışlı olan, standart kütüphaneden std :: stack şablonunu anlamaktır. Bu şekilde idiomatik olarak Java'ya ilham veren kodun düzeltilmesi, bir hipopotamın nasıl dans edileceğini öğretmek gibidir.
katma yazar Alexandre C., kaynak
@Ben Voigt: Neden sadece pop + pop ve pop değil anlamak std :: stack (ve muhtemelen ne hakkında konuştuğunuz) tek inceliktir. Ama anladım. Ayrıca @Dylan, void 'i döndürmek için Pop yöntemini düzeltmeniz gerekir.
katma yazar Alexandre C., kaynak
@Dylan: Asıl nokta, öğeyi aynı işlevde döndürüp döndürememenizdir. Üst nesneyi (dönüş ifadesinde) kopyalamak herhangi bir nedenden dolayı başarısız olursa (ör. <�İ> bir istisna atar ), yığının el değmeden kalmasını istersiniz. Bu nedenle, üst öğeyi almak için üst ve üst öğeyi kaldırmak için pop değerini girersiniz. Bu, std :: stack sınıfının yaptığı ve insanların yığın sınıflarını kendilerinin uygulamamalarını söyleyen evcil hayvan nedenlerimden biri.
katma yazar Alexandre C., kaynak
@BenVoigt Benim kötü, sadece Üst bir başvuru döndüren gerçeği düşünmüştüm. Bu durumda Pop 'a döndürmeniz gerekir, yoksa başvuru sarkıtılır. (Ayrıca, std :: stack > , burada istenen semantikleri sağlar). Aynı zamanda eşzamanlı koleksiyonlar başka bir solucan torbasıdır (kendimi uygulamak istemediğim).
katma yazar Alexandre C., kaynak

1 cevap

Artık düzeltmeye çalıştığınızı belirttiğinizden, şunu öneriyorum:

  • 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.

Bu noktada tasarımı hurdaya çıkarmanın yolundayız.

3
katma