H/W: C ++ қатесі «дерексіз негіздік сыныпты инициализациялауға тырысады»

StackAssLinkedList деп аталатын сыныпты инициализациялауға тырысамыз, ол дерексіз класс Stack-тың сыныбына жатқызылуы керек (сынақ коды, ол жерде қол жетімді: http://www.brpreiss.com/books/opus4/ ).

Алайда, осы кодты негізгі ():

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

класс Контейнер:

#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: Компилятор Салыстыру() әдісіндегі Object әдісі ешқандай туынды сыныптарда орындалмайтынын айтады. Дегенмен, бұл функция «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

Бірақ Stack Wrapper-дан мұрагерлік емес - сондықтан, бұл дегеніміз, Stack-дің басқа әдісі CompareTo әдісі қажет пе? Бастапқы автордың бұл жұмысқа қалай ие болғаны туралы білмеймін (бас сызаттар).

0
Контейнердің анықтамасын көрсетуіңіз керек
қосылды автор Puppy, көзі
@Alexandre: Мен осы сыныпқа (Data Structures) дейін STL курсын алдым және сенемін, егер мен қолдана алсам (STL рұқсат етілмеген)
қосылды автор dtg, көзі
@Alexandre: шынымен? Мен нысанды (немесе нысанға сілтегішті) қайтарғыңыз келетін стака элементін ұрып кеткеннен кейін ойладым ба?
қосылды автор dtg, көзі
@Ben Voigt Әдетте сіздің ұсынысыңызды қабылдаймын, бірақ осы тапсырманың мақсаты - бұрыннан жұмыс істемейтін және дұрыс емес нәрсені анықтайтын ескі кодты қарау (және оны түзету). Мәселе қайда екендігін көрсетіп, қазіргі дизайнды толығымен қырқып кетпестен қалай шешуге болатынын білмейсіз!
қосылды автор dtg, көзі
Әрине. CompareTo() Wrapper-да жүзеге асырылады (ол Object-тан мұраланған), бірақ Stack мұрнынан мұрагерлікке ие болып көрінбейді ... hmmm ... қайтадан бұл біреу жазған бастапқы код, бұл оны түсінуге тырысамын.
қосылды автор dtg, көзі
@Ben Voigt: «Объект» деген мәселе туындайды: «int Object :: CompareTo (const Object & const): дерексіз
қосылды автор dtg, көзі
@Dylan: Мүмкін, StackAsLinkedList иемденеді Stack мұрагерлері Container иеленеді Object ? Содан кейін жол бойында, CompareTo StackAsLinkedList дегенді білдіреді.
қосылды автор Ben Voigt, көзі
@Dylan: Енді неге сәтсіздікке түсетінін түсінетін болсаңыз, жақсы коды түсінуге ұмтылуға кеңес беремін. Бұл кодтың тек сыналғаны ғана емес, қорқынышты стилі де бар. Мүмкін, ол бірдей конструкцияны бірнеше тілде қолдануға тырысады, ал C ++ коды - C ++ дизайнымен емес, Java нұсқасының жаман аудармасы.
қосылды автор Ben Voigt, көзі
Сіз қандай компиляторды қолданасыз? MSVC ++ немесе gcc жаңа нұсқасы бар болса, Object & Pop() переопределите жаза аласыз және компилятор сәйкес келмейтінін білуге ​​мүмкіндік береді. Сондай-ақ, компилятордың осы қателіктермен бірге шыққаны туралы ескертулерді көрсету керек.
қосылды автор Ben Voigt, көзі
@Alexandre: Мүмкін қарапайым әшекейленген стек класын түсіну арқылы бастадым және негізгі операцияларды жақсы түсінгеннен кейін ғана STL-нің іске асырылуының барлық нәзіктіктеріне ауысадым.
қосылды автор Ben Voigt, көзі
@DeadMG: Менің ойымша, сізге жауап беру керек, бұл мәселе дерлік анық.
қосылды автор Ben Voigt, көзі
@Alexandre: Көрсеткішті көшіру - лақтырылмайды. Бұл коллекцияда көрсеткіштер ғана бар (полиморфизм үшін қажет), элементтердің ешқандай көшірмесі жасалмайды. Дизайн шешімі үшін негізді түсіну және ол қолданылмайтын жерде оны бекіту және оны қол сұғылмайтын ереже ретінде қабылдау маңызды.
қосылды автор Ben Voigt, көзі
@Dylan: Жақсысың, Александр тек қана құндылықтарды сақтай отырып, көрсеткіштерді сақтайтын коллекцияларға емес, жинақтар туралы айтады. Коллекцияңыз көрсеткіштерді сақтайды және көрсеткішті Pop ішінен қайтарады.
қосылды автор Ben Voigt, көзі
Шын мәнінде, top және pop үшін бөлек әрекеттерді орындау бір мезгілде жинақтарға қатысты қате болып табылады.
қосылды автор Ben Voigt, көзі
@AlexandreC: Сілтеме қауіпті емес, нысан динамикалық түрде бөлінген және оның мекен-жайы delete операндысы ретінде пайдаланылатынға дейін бар болады. Көрсеткішті қолдану - бұл әлдеқайда жақсы стиль.
қосылды автор Ben Voigt, көзі
Container анықтамасы қандай?
қосылды автор bdonlan, көзі
@Ben Voigt, Dylan: стандартты кітапханадан std :: stack үлгісін түсіну жақсы әрі пайдалы. Java-ның шабыттанған кодты дәл осылай бекіту, мысалы, би билеуге үйрету сияқты.
қосылды автор Alexandre C., көзі
@Ben Voigt: Не үшін жоғарғы + поп-ны түсініп, жай ғана поп болып табылмайды, std :: stack (және сіз айтып отырған нәрсе). Бірақ мен сіздің ойыңызды аламын. Сондай-ақ, @Dylan, void қайтару үшін Pop әдісін шынымен түзетіңіз.
қосылды автор Alexandre C., көзі
@Dylan: Мәселе мынада, сіз бірдей функциядағы элементті қайтара алмайсыз. Егер жоғарғы нысанды (қайтару мәлімдемесінде) кез келген себеппен (мысалы, алып тастайды ) сәтсіздікке ұшырасаңыз, стека тиіп кетпесін. Сондықтан жоғарғы элемент алу үшін top және pop жоғарғы элементін жоюға мүмкіндік бересіз. std :: stack класы осылай жасайды және адамдарға стек кластарын өздігінен іске асырмауды айтуға арналған үй жануарларының себептері.
қосылды автор Alexandre C., көзі
@BenVoigt Менің жаман емес, тек Top сілтемесін қайтару фактісін ғана ойладым. Бұл жағдайда сіз міндетті Pop көрсеткішін қайтарыңыз немесе сілтеме сөнеді. (Сондай-ақ, std :: stack > ) мұнда қажетті семантиканы қамтамасыз етеді. Сондай-ақ, бір мезгілде жинақтар - бұл құрттың тағы бір қаптамасы (мен оны ешқашан never өзім жүзеге асырғым келеді).
қосылды автор 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
қосылды