Циркулярные декларации и циркулярные ссылки

У меня проблемы с этим фрагментом кода, который оценивает числовые операции. Я попытался найти, но ни один ответ не показался мне полезным.

Базовый класс для представления операции:

Operacija.h:

#pragma once
#include <iostream>
using namespace std;

class Operacija
{
protected:
char* naziv;
int drugiO;
Operacija* suprotna;
public:
Operacija* retOp() { return this->suprotna; }
int retD() { return this->drugiO; }
void printOp()
{
cout << "Ime operacije: " << this->naziv << endl;
cout << "Drugi operand: " << this->drugiO << endl;
cout << "Ime suprotne operacije: " << this->suprotna->naziv << endl;
}
virtual int DoOperation(int op1, int op2) = 0;
};

Этот производный класс предназначен для умножения:

Mnozenje.h:

//this is .h for 1st class
#pragma once
#include "Operacija.h"#include "Deljenje.h"
class Mnozenje : public Operacija
{
public:
Mnozenje(int b);
int DoOperation(int op1, int op2);
};

Mnozenje.cpp:

#include "Deljenje.h"#include "Mnozenje.h"class Deljenje;
Mnozenje::Mnozenje(int b)
{
Deljenje* a = new Deljenje(b);
naziv = "Mnozenje";
suprotna = a;
if (b == 0)
{
cout << "operand ne sme biti 0, stoga je stavljen na ";
cout << "default tj. postavljen na vrednost 1!" << endl;
drugiO = 1;
}
else
drugiO = b;
}

int Mnozenje::DoOperation(int op1, int op2)
{
int a = 0;
a = op1 * op2;
return a;
}

И этот производный класс для разделения:

Deljenje.h:

#pragma once
#include "Operacija.h"#include "Mnozenje.h"

class Deljenje : public Operacija
{
public:
Deljenje(int a);
int DoOperation(int op1, int op2);
};

Deljenje.cpp:

#include "Deljenje.h"#include "Mnozenje.h"class Mnozenje;

Deljenje::Deljenje(int a)
{
Mnozenje* b = new Mnozenje(a);
naziv = "Deljenje";
suprotna = b;
if (a == 0)
{
cout << "operand ne sme biti 0, stoga je stavljen na default tj.     postavljen na vrednost 1!" << endl;
drugiO = 1;
}
else
drugiO = a;
}

int Deljenje::DoOperation(int op1, int op2)
{
int a = 0;
a = op1 / op2;
return a;
}

Я понимаю, почему это не работает, и я попытался просто объявить указатели вместо инициализации suprotna член для Mnozenje а также Deljenje, Но у меня есть другой класс, являющийся контейнером типа Operacija и я не могу иметь неинициализированные указатели, потому что мне нужно вызвать какую-то другую функцию, используя suprotna,

-2

Решение

По вашему вопросу возникли три проблемы:

  • Первый касается ошибок компиляции из-за ненужных циклических ссылок. Реализация ответа БЕЗ ИМЕНИ полностью решить эту тему как продемонстрировано здесь.

  • Второй — это ошибка сегментации, которая возникает каждый раз, когда вы создаете Mnozenje или Deljene: например, если вы создаете Mnozenje из int, тогда вы создадите прямо в начале его строительства новый объект Deljenje который создаст прямо в начале своего строительства новый Mnozenje, который будет создавать … пока не произойдет стекопотока.

  • Третья проблема — ваше намеренное использование наследования. Имея контейнер Operacija вместо Operacija* приведет к нарезка и он обречен на провал.

Предложения:

Я это понимаю Mnozenje это умножение и Deljene разделение, и что вы пытаетесь хранить в suprotnaобратная операция.

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

Идея будет примерно такой:

class Mnozenje : public Operacija
{
public:
Mnozenje(int b, Operacija* rev=nullptr);
int DoOperation(int op1, int op2);
};

Mnozenje::Mnozenje(int b, Operacija* rev)
{
naziv = "Mnozenje";
suprotna = rev==nullptr ? new Deljenje(b, this) : rev;
...
}

// and the same kind of change for Deljenje

В этом случае, вместо повторения навсегда, вы создаете циклическую ссылку между связанными объектами.

ВНИМАНИЕ: Этот обходной путь сделает разрушение объектов немного более сложным. Если у вас есть достаточно времени для экзамена, рассмотрите возможность изменения дизайна:

  • оставьте два указателя для обратной операции: один для вновь выделенных объектов, другой для указания на исходную операцию. В этом случае вы могли бы улучшить, используя shared_ptr а также weak_ptr чтобы помочь вам управлять памятью;
  • или создайте обратную операцию только тогда, когда это необходимо (то есть не при построении, а как результат функции-члена);
  • или отделите в вашей структуре данных операции от операнда;
  • или не создавайте полностью обратную операцию, добавив UndoOperation() функция-член.
2

Другие решения

Вам не нужно #include "Mnozenje.h" в Deljenje.h а также #include "Deljenje.h" в Mnozenje.h, Тот факт, что вы используете класс в .cpp Файл не означает, что вы должны иметь определение этого класса в .hpp файл.

Вам также не нужно писать объявления таких классов: class Deljenje;потому что включает в себя (например, #include "Deljenje.h") дает вам определения этих классов.

Кажется, что не совсем осознает тот факт, как работает работает.
Это довольно просто. Включить просто скопировать весь указанный файл в место, где находится #include директивы. Вы можете прочитать больше об этом здесь: Как работает процесс компиляции / компоновки?

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector