Шаблон проектирования декоратора, ошибка функции

#c #class #initialization #decorator

#c #класс #инициализация #декоратор #c

Вопрос:

Это домашнее задание … Я не прошу ответов, у меня просто ошибка, с которой я не уверен, что делать. Спасибо!

Ошибка, о которой идет речь, вероятно, не имеет ничего общего с самим назначением, но в любом случае вот описание назначения:

Я работаю над заданием (на C ), предназначенным для обучения использованию шаблона дизайна декоратора на классическом примере пиццы с начинкой. (Мой профессор, возможно, также поднял его прямо из http://simplestcodings.com/2010/12/26/decorator-design-pattern-example-ni-c /). Я столкнулся с небольшой проблемой, с которой мне было интересно, может ли кто-нибудь мне помочь.

У меня есть объект главного меню (пиццерия), который принимает входные данные от пользователя и выполняет желаемые действия с пиццей. Пользователи начинают с базовой пиццы, а затем могут добавлять к ней начинки, пока она не будет готова. Итак, первое, что делает моя функция «newPizza», это объявляет новую пиццу как Plain , которая является подклассом абстрактного класса Pizza .

Затем они могут указать начинки на свой выбор. Каждый раз в Pizza функцию отправляется указатель на один и тот же addToppings() объект, добавляется новое оформление и возвращается указатель. Каждое украшение наследуется от ценовой категории, которая наследуется от pizzaToppings , которая наследуется от Pizza .

Это соответствующая часть основной функции заказа:

 Pizza* Menu::newPizza()
{
cout << "nNew Pizza";

//accept the next choice
int choose = 0;

//create the new pizza
Plain * currentPizza = new Plain();

//until they choose to end the order
while (choose != 3)
{
    //accept the choice
    cin >> choose;

    switch (choose)
    {
        //if they want to add a new topping
    case 1:
        {
            //add topping to current pizza
           //and this is where the problem is spotted by the compiler
            addTopping(currentPizza);
            break;
        }
  

Проблема в том, что когда я пытаюсь отправить указатель currentPizza на функцию addTopping() , я получаю
«Ошибка проверки во время выполнения # 3 — переменная ‘currentPizza’ используется без инициализации».

Разве я только что не инициализировал его прямо там, в строке 7?

Если я нажимаю «продолжить», программа продолжает работать, но я получаю ту же ошибку каждый раз, когда вызываю функцию. Это просто синтаксическая ошибка где-то, или у меня здесь какая-то реальная проблема?

Спасибо!!

[править:]

Функция addTopping():

 Pizza* Menu::addTopping(Pizza* thisPizza)
{
cout << "nAdd topping";

//declare choose int
int choose = 0;

//accept number of topping
cin >> choose;

//decide which one to add
switch (choose)
{

//mozzarella
case 1:
    {
        thisPizza = new Mozzarella(thisPizza);
        break;
    }
//mushrooms
case 2:
    {
        thisPizza = new Mushrooms(thisPizza);
        break;
    }

//another 13 possible toppings, won't bore you with the details ;)

}

cout << "nEnd add toppingn";

return thisPizza;
}
  

Комментарии:

1. Какова реализация addTopping()? это может быть актуально

2. Есть ли у Plain класса некоторые переменные-члены POD, которые не инициализируются?

3. @Chris, нет, все, что у него есть, находится в его конструкторе

4. @BIU: У вас утечка довольно большого объема памяти. 🙂

5. Я думаю, что есть проблемы с вашей иерархией классов, независимо от того, работает ли программа на самом деле. Например, вы говорите, что начинка для пиццы наследуется от Pizza, но обычно наследование следует использовать для моделирования отношения «есть-а», а начинка для пиццы — это не пицца.

Ответ №1:

Есть ли у вас currentPizza также объявленный как поле Pizza класс, и вы используете это где-то еще? Если это так, то currentPizza вы обновляете в newPizza специфично для этого метода, и вам нужно сделать просто currentPizza = new Plain(); вместо объявления новой currentPizza переменной в области действия метода.

Кроме того, в вашем addTopping методе вы обновляете только аргумент thisPizza , который является копией указателя currentPizza .

Вам нужно сделать:

 currentPizza = addTopping(currentPizza);
  

Комментарии:

1. Я не заметил, что это не было опубликовано. Я предполагаю, что я скопировал из неправильной версии, потому что это строка, которая сейчас есть в моем коде. Спасибо 🙂

Ответ №2:

Если вы передадите указатель по значению (что вы и делаете), он примет это значение указателя и присвоит ему новую пиццу. Это значение не совпадает с тем, которое найдено в строке 7 выше. Например:

 int bar = new int(3);
void  doSomething(int *foo){ foo = new int(5); } //memory leak here
doSomething(bar);
  

панель по-прежнему равна 3. Это фактически то, что вы делаете.

Вы хотите передать указатель по ссылке:

 void doSomething(int **foo){ delete *foo; *foo = new int(5); }
  

Обновить:

Поскольку вы хотели бы структуру вложенного класса, в которой дочерний класс сохраняет запись базового класса полиморфным образом…

 void doSomething(MyClass **foo){ *foo = new MyChildClass(*foo); }
  

Я надеюсь, что в рамках вашего определения в дочерних классах вы убедились, что правильно обрабатываете высвобождение ресурсов (то есть указателей). Я бы предложил рассмотреть возможность включения интеллектуального указателя, но это может быть больше, чем вам нужно для этого назначения.

Комментарии:

1. Я понимаю, о чем вы говорите, но причина, по которой я этого не сделал, заключается в том, что я должен иметь возможность добавлять начинку за начинкой в одну и ту же пиццу. Разве это не означало бы, что я каждый раз начинал бы с нуля?

2. @BIU Я вижу, позвольте мне обновить ответ, чтобы отразить то, что вы пытаетесь сделать со своей структурой классов.

Ответ №3:

Одна ошибка заключается в том, что в Menu::newPizza() вы этого не делаете : currentPizza = addTopping(currentPizza);

Также у вас произошла утечка памяти, поскольку вы создаете новый объект в куче, не удаляя старый.

Кстати, похоже, что плохой дизайн возвращает новую пиццу из метода addTopping.