http://www.brpreiss.com/books/opus4/ ). Проте виникає"> http://www.brpreiss.com/books/opus4/ ). Проте виникає"> http://www.brpreiss.com/books/opus4/ ). Проте виникає" />

H/W: C ++ Помилка "намагається ініціалізувати абстрактний базовий клас"

Спроба ініціалізувати клас, який називається StackAsLinkedList, який повинен бути похідним класом абстрактного класу Stack (тестовий код, який доступний тут: nofollow "> 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());
}

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

#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: Схоже, що компілятор каже, що метод CompareTo() в 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 - тому я припускаю, що це означає, що інший метод CompareTo повинен бути реалізований для Stack? Не впевнений, як оригінальний автор отримав це для роботи (голова подряпини).

0
Потрібно показати визначення контейнера
додано Автор Puppy, джерело
@Alexandre: Я взяв курс на 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: Напевно StackAsLinkedList успадковує Стек , успадковує Контейнер , успадковує Об'єкт ? Потім, десь у дорозі, потрібно визначити, що означає CompareTo для StackAsLinkedList .
додано Автор Ben Voigt, джерело
@Dylan: Тепер, коли ви розумієте, чому це не вдається, я пропоную вам перейти до розуміння гарного коду. Цей код не тільки не випробовується, він демонструє жахливий стиль. Можливо, тому, що він намагається використовувати той же дизайн на декількох мовах, а код C ++ насправді є поганим перекладом версії Java, а не C + +.
додано Автор Ben Voigt, джерело
Який компілятор ви використовуєте? З MSVC ++ або більш новою версією gcc, ви можете написати Object & Pop() override; Вам також потрібно показати будь-які попередження, що компілятор плюнув поруч з цією помилкою.
додано Автор Ben Voigt, джерело
@Alexandre: Я б, напевно, починав з розуміння простого класу шаблонів, і тільки переходив до всіх тонкостей реалізації STL після того, як основні операції добре зрозуміли.
додано Автор Ben Voigt, джерело
@DeadMG: Я думаю, що вам потрібно зробити відповідь, це майже напевно буде проблемою.
додано Автор Ben Voigt, джерело
@Alexandre: Копіювання вказівника не викидає. Ця колекція містить тільки покажчики (необхідні для поліморфізму), копії елементів не робляться. Розуміння обґрунтування проектного рішення, а де він не застосовується, є більш важливим, ніж фіксація на ньому та перетворення його на недоторкане правило.
додано Автор Ben Voigt, джерело
@Dylan: Ви добре, про що говорить Александр, стосується лише колекцій, які зберігають значення, а не колекцій, які зберігають покажчики. У вашій колекції зберігаються покажчики, а повернення покажчика з Pop - це нормально.
додано Автор Ben Voigt, джерело
Фактично, наявність окремих операцій для верхньої і pop є серйозною помилкою, коли йдеться про паралельні колекції.
додано Автор Ben Voigt, джерело
@AlexandreC: посилання не висить, об'єкт динамічно виділяється і продовжуватиме існувати, поки його адреса не буде використовуватися як операнд delete . Домовилися, що використання покажчика набагато краще за стиль.
додано Автор Ben Voigt, джерело
яке визначення Container ?
додано Автор bdonlan, джерело
@Ben Voigt, Dylan: краще і кориснішим є розуміння шаблону std :: stack зі стандартної бібліотеки. Виправлення ідіоматично натхненного Java-коду, подібного до цього, подібне до навчання гіппопота, як танцювати.
додано Автор Alexandre C., джерело
@Ben Voigt: Розуміння того, чому top + pop, а не просто pop, є єдиною тонкістю std :: stack (і, можливо, про те, про що ви говорите). Але я розумію вашу думку. Також @Dylan, ви повинні дійсно виправити, що Поп метод, щоб повернути void .
додано Автор Alexandre C., джерело
@Dylan: Справа в тому, що ви не можете скопіювати і повернути елемент у тій самій функції. Якщо копіювання верхнього об'єкта (у операторі повернення) не відбувається з будь-якої причини (тобто кидає виняток ), ви хочете, щоб стек залишався недоторканим. Таким чином, ви надаєте верхній для отримання верхнього елемента, а pop для видалення верхнього елемента. Ось як робить клас std :: stack , і один з моїх причин, що дозволяють людям не застосовувати самі класи класу стеків.
додано Автор 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.

Ми добре на шляху до scrapping проект цим пунктом.

3
додано
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147