H/W: C ++ Fout "probeert abstracte basisklasse te initialiseren"

Probeert een klasse genaamd StackAsLinkedList te initialiseren, wat een afgeleide klasse van de abstracte klasse Stack zou moeten zijn (testcode die hier beschikbaar is: http://www.brpreiss.com/books/opus4/ ).

Ik krijg echter een fout bij het proberen om deze code in main() te instantiëren:

StackAsLinkedList stack;

error C2259: 'StackAsLinkedList' : cannot instantiate abstract class

Ik ben hier verward over, omdat ik dacht dat StackAsLinkedList is gedefinieerd als een afgeleide klasse van 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 

De implementatie:

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

klasse 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

EDIT: het lijkt erop dat de compiler zegt dat de methode CompareTo() in Object niet is geïmplementeerd in een van de afgeleide klassen. Deze functionaliteit is echter geïmplementeerd in de afgeleide klasse van Object genaamd "Wrapper":

#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

Maar Stack ervaart niet van Wrapper - dus ik vermoed dat dit betekent dat een andere CompareTo-methode moet worden geïmplementeerd voor Stack? Niet zeker hoe de oorspronkelijke auteur dit heeft laten werken (krassende kop).

0
U moet de definitie van Container tonen
toegevoegd de auteur Puppy, de bron
@Alexandre: ik volgde een cursus STL voorafgaand aan deze klasse (gegevensstructuren) en geloof me, ik zou STL volledig gebruiken als dat mogelijk was (geen STL toegestaan)
toegevoegd de auteur dtg, de bron
@Alexandre: echt? Ik dacht na het knallen van een element van de stapel dat je terug wilt krijgen het object (of een wijzer naar het object)?
toegevoegd de auteur dtg, de bron
@Ben Voigt Normaal gesproken neem ik je suggestie, maar het ogenschijnlijke doel van deze opdracht is om te kijken naar oude code die niet echt meer werkt en erachter te komen wat er mis is (en het te repareren). Uitgezocht waar het probleem zit, niet zeker hoe je het op kunt lossen zonder het huidige ontwerp volledig te schrappen!
toegevoegd de auteur dtg, de bron
Inderdaad. CompareTo() is geïmplementeerd in Wrapper (die erft van Object), maar het lijkt er niet op dat Stack erft van Wrapper ... hmmm ... opnieuw is dit grotendeels de broncode die iemand anders heeft geschreven - ik probeer het te begrijpen.
toegevoegd de auteur dtg, de bron
@Ben Voigt: het lijkt erop dat het een probleem is met "Object": 'int Object :: CompareTo (const Object &) const': is abstract
toegevoegd de auteur dtg, de bron
@Dylan: waarschijnlijk overleeft StackAsLinkedList erft Stack erft Container erft Object ? Dan moet je ergens op de weg bepalen wat CompareTo betekent voor een StackAsLinkedList .
toegevoegd de auteur Ben Voigt, de bron
@Dylan: Nu je begrijpt waarom het faalt, raad ik je aan verder te gaan met het begrijpen van goede code. Deze code is niet alleen duidelijk getest, maar vertoont ook een vreselijke stijl. Waarschijnlijk omdat het hetzelfde ontwerp in meerdere talen probeert te gebruiken, en de C ++ -code is eigenlijk een slechte vertaling van de Java-versie, geen C ++ -ontwerp.
toegevoegd de auteur Ben Voigt, de bron
Welke compiler gebruikt u? Met MSVC ++ of een nieuwere versie van gcc kun je Object & Pop() negeren; en de compiler laat het weten als het niet overeenkomt. U moet ook eventuele waarschuwingen weergeven die de compiler naast die fout uitspuwde.
toegevoegd de auteur Ben Voigt, de bron
@Alexandre: Ik zou waarschijnlijk beginnen met het begrijpen van een eenvoudige sjabloonklasse met sjablonen en pas verder gaan met alle subtiliteiten van de STL-implementatie nadat de basisbewerkingen goed zijn begrepen.
toegevoegd de auteur Ben Voigt, de bron
@DeadMG: ik denk dat je daar een antwoord op moet geven, het is bijna zeker het probleem.
toegevoegd de auteur Ben Voigt, de bron
@Alexandre: het kopiëren van een aanwijzer is niet-werpen. Deze verzameling bevat alleen verwijzingen (noodzakelijk voor polymorfisme), er worden geen kopieën van elementen gemaakt. Het begrijpen van de beweegredenen voor een ontwerpbeslissing, en waar dit niet van toepassing is, is belangrijker dan er op te fixeren en er een onschendbare regel van te maken.
toegevoegd de auteur Ben Voigt, de bron
@Dylan: Het gaat goed, waar Alexandre het over heeft, verwijst alleen naar collecties die waarden opslaan, geen collecties die pointers opslaan. Uw verzameling slaat verwijzingen op en het retourneren van de aanwijzer van Pop is prima.
toegevoegd de auteur Ben Voigt, de bron
In feite is het hebben van afzonderlijke bewerkingen voor top en pop een ernstige fout als het gaat om gelijktijdige collecties.
toegevoegd de auteur Ben Voigt, de bron
@AlexandreC: de referentie is niet bungelen, het object wordt dynamisch toegewezen en blijft bestaan ​​totdat het adres wordt gebruikt als de operand van verwijderen . Overeengekomen dat het gebruik van een aanwijzer een veel betere stijl is.
toegevoegd de auteur Ben Voigt, de bron
wat is de definitie van container ?
toegevoegd de auteur bdonlan, de bron
@Ben Voigt, Dylan: beter en nog nuttiger is om de std :: stack -sjabloon uit de standaardbibliotheek te begrijpen. Het idiomatisch fixeren van op Java geïnspireerde code zoals deze is als het leren van een hippo hoe te dansen.
toegevoegd de auteur Alexandre C., de bron
@Ben Voigt: Begrijpen waarom top + pop en niet alleen pop de enige subtiliteit is van std :: stack (en waarschijnlijk waar je het over hebt). Maar ik snap je punt. Ook @Dylan zou je die Pop -methode echt moeten repareren om void te retourneren.
toegevoegd de auteur Alexandre C., de bron
@Dylan: het punt is dat je het element niet kunt knallen en teruggeven in dezelfde functie. Als het kopiëren van het bovenste object (op de instructie return) om welke reden dan ook mislukt (dwz. genereert een uitzondering ), wilt u dat de stapel niet wordt aangeraakt. Daarom geeft u top op voor het ophalen van het bovenste element en pop voor het verwijderen van het bovenste element. Dit is hoe de klasse std :: stack het doet en een van mijn redenen is om mensen te vertellen om zelf geen stack classes te implementeren.
toegevoegd de auteur Alexandre C., de bron
@BenVoigt Mijn slechte, ik heb alleen overwogen dat Top een referentie retourneert. In dit geval geeft u moet een aanwijzer terug van Pop of de verwijzing wordt bengelend. (Ook zou std :: stack > hier de gewenste semantiek geven). Ook gelijktijdige collecties zijn een andere zak met wormen (die ik nooit zelf zou willen implementeren).
toegevoegd de auteur Alexandre C., de bron

1 antwoord

Omdat je nu hebt uitgelegd dat je het probeert op te lossen, raad ik aan:

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

We zijn goed op weg om het ontwerp op dit punt te schrappen.

3
toegevoegd