通函和循环引用

时间:2015-08-20 20:50:28

标签: c++ inheritance constructor circular-reference

我在使用这段代码时遇到问题,这些代码将评估数值运算。我试着搜索,但没有答案似乎有帮助。

表示操作的基类是:

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成员MnozenjeDeljenje。但我有另一个类是类型为Operacija的数组的容器,我不能有未初始化的指针,因为我需要使用suprotna调用其他函数。

2 个答案:

答案 0 :(得分:2)

您的问题引发了三个问题:

  • 第一个是关于编译错误,因为不必要的循环拒绝。实施 NO_NAME 的答案可以完全解决此问题demonstrated here

  • 第二个是每次创建MnozenjeDeljene时都会发生的细分错误:例如,如果您从{{1}创建Mnozenje然后你将在构造开始时创建一个新对象int,它将在构造开始时创建一个新的Deljenje,它将创建...直到发生堆栈溢出。

  • 第三个问题是您对继承的预期用途。拥有Mnozenje而不是Operacija的容器会导致slicing,并且注定要失败。

<强>建议:

我理解Operacija*是乘法而Mnozenje是一个除法,并且您尝试将Deljene存储在反向操作中。

因此,我建议你预见一个带有可选参数的构造函数,这样当你创建一个反向操作时,你可以将原始操作指示为reverse。

这个想法是这样的:

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成员函数来避免完全创建反向操作。

答案 1 :(得分:1)

$("h2[style='color=#ccc; font-size=12px; margin=10px;']"); 中的#include "Mnozenje.h"Deljenje.h中的#include "Deljenje.h"不需要Mnozenje.h。您在.cpp文件中使用类的事实并不意味着您必须在.hpp文件中定义此类。

您也不需要编写类似这样的类的声明:class Deljenje;,因为includes(例如#include "Deljenje.h")为您提供了这些类的定义。

似乎不太了解包含作品的事实。 这很简单。包括只将整个指定文件复制到#include指令的位置。您可以在此处详细了解:How does the compilation/linking process work?