Ошибки сборки твердости из-за круговой зависимости среди классов

Я нашел одно решение для этого. следуйте ниже:

// I use the scrollbarX to create a horizontal scrollbar 
chart.scrollbarX = new am4core.Scrollbar();

// here I set the scroolbar bottom the chart
chart.scrollbarX.parent = chart.bottomAxesContainer;

//here I chose not to show the startGrip (or button that expand the series from chart)
chart.scrollbarX.startGrip.hide();
chart.scrollbarX.endGrip.hide();

// here I set the start and end scroolbarX series that I would like show in chart initially
chart.scrollbarX.start = 0;
chart.scrollbarX.end = 0.25;

// here I chose not to show the zoomOutButton  that appear above from chart
chart.zoomOutButton = new am4core.ZoomOutButton();
chart.zoomOutButton.hide();

Итак, мой полный метод построения диаграммы таков:

private buildChart(dataChart) {

  /* Chart code */
  // Themes begin
  am4core.useTheme(am4themes_animated);
  // Create chart instance
  const chart = am4core.create('chartdiv', am4charts.XYChart);

  for (const data of dataChart) {
    chart.data.push(data);
  }

  // Create axes
  const categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
  categoryAxis.dataFields.category = 'model';
  categoryAxis.renderer.grid.template.location = 0;

  const valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
  valueAxis.renderer.inside = true;
  valueAxis.renderer.labels.template.disabled = true;
  valueAxis.min = 0;

  // Create series
  function createSeries(field, name) {

    // Set up series
    const series = chart.series.push(new am4charts.ColumnSeries());
    series.name = name;
    series.dataFields.valueY = field;
    series.dataFields.categoryX = 'model';
    series.sequencedInterpolation = true;

    // Make it stacked
    series.stacked = true;

    // Configure columns
    series.columns.template.width = am4core.percent(60);
    series.columns.template.tooltipText = '[bold]{name}[/]\n[font-size:15px]{categoryX}: {valueY}';

    // Add label
    const labelBullet = series.bullets.push(new am4charts.LabelBullet());
    labelBullet.label.text = '{valueY}';
    labelBullet.locationY = 0.5;

    return series;
  }

  createSeries('DISCONNECTED', 'DISCONNECTED');
  createSeries('AVAILABLE', 'AVAILABLE');

  // Legend
  chart.legend = new am4charts.Legend();
  chart.scrollbarX = new am4core.Scrollbar();
  chart.scrollbarX.parent = chart.bottomAxesContainer;
  chart.scrollbarX.startGrip.hide();
  chart.scrollbarX.endGrip.hide();
  chart.scrollbarX.start = 0;
  chart.scrollbarX.end = 0.25;

  chart.zoomOutButton = new am4core.ZoomOutButton();
  chart.zoomOutButton.hide();

}

Следуйте распечатке ниже, показывая, как это получилось

enter image description here

332
задан StoryTeller - Unslander Monica 12 October 2017 в 04:20
поделиться

4 ответа

Способ думать об этом состоит в том, чтобы "думать как компилятор".

Предполагают, что Вы пишете компилятор. И Вы видите код как это.

// file: A.h
class A {
  B _b;
};

// file: B.h
class B {
  A _a;
};

// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
  A a;
}

, Когда Вы компилируете файл .cc (помнят, что .cc а не .h является единицей компиляции), необходимо выделить место для объекта A. Так, хорошо, сколько пространства тогда? Достаточно сохранить B! Каков размер B тогда? Достаточно сохранить A! Ой.

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

можно повредить его, позволив компилятору вместо этого зарезервировать столько пространства, сколько это знает о первичном - указатели и ссылки, например, будут всегда составлять 32 или 64 бита (в зависимости от архитектуры) и поэтому если бы Вы заменили (любой один) указателем или ссылкой, то вещи были бы большими. Скажем, мы заменяем в [1 111]:

// file: A.h
class A {
  // both these are fine, so are various const versions of the same.
  B& _b_ref;
  B* _b_ptr;
};

Теперь вещи лучше. Несколько. main() все еще говорит:

// file: main.cc
#include "A.h"  // <-- Houston, we have a problem

#include, для всех степеней и целей (если Вы вынимаете препроцессор) просто копирует файл в .cc. Таким образом, действительно .cc похож:

// file: partially_pre_processed_main.cc
class A {
  B& _b_ref;
  B* _b_ptr;
};
#include "B.h"
int main (...) {
  A a;
}

Вы видите, почему компилятор не может иметь дело с этим - он понятия не имеет, что B - он даже не видел символ прежде.

Так позволяют нам сказать компилятор приблизительно [1 115]. Это известно как предописание и обсуждено далее в [1 121] этот ответ .

// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
  A a;
}

Это работы . Это не большое . Но в этой точке у Вас должно быть понимание проблемы циклической ссылки и что мы сделали для "зафиксированного" его, хотя фиксация плоха.

причина, эта фиксация плоха, состоит в том, потому что следующий человек к [1 116] должен будет объявить B, прежде чем они смогут использовать ее и получат ужасное #include ошибка. Поэтому давайте переместим объявление в [1 142] сам A.h.

// file: A.h
class B;
class A {
  B* _b; // or any of the other variants.
};

И в [1 143] B.h, в этой точке, Вы можете всего #include "A.h" непосредственно.

// file: B.h
#include "A.h"
class B {
  // note that this is cool because the compiler knows by this time
  // how much space A will need.
  A _a; 
}

HTH.

270
ответ дан Community 23 November 2019 в 00:45
поделиться

Можно избежать ошибок компиляции, если Вы удаляете определения метода из заголовочных файлов и позволяете классам содержать только объявления метода и переменные объявления/определения. Определения метода должны быть помещены в .cpp файл (точно так же, как в инструкции по лучшей практике говорится).

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

//A.h
#ifndef A_H
#define A_H
class B;
class A
{
    int _val;
    B* _b;
public:

    A(int val);
    void SetB(B *b);
    void Print();
};
#endif

//B.h
#ifndef B_H
#define B_H
class A;
class B
{
    double _val;
    A* _a;
public:

    B(double val);
    void SetA(A *a);
    void Print();
};
#endif

//A.cpp
#include "A.h"
#include "B.h"

#include <iostream>

using namespace std;

A::A(int val)
:_val(val)
{
}

void A::SetB(B *b)
{
    _b = b;
    cout<<"Inside SetB()"<<endl;
    _b->Print();
}

void A::Print()
{
    cout<<"Type:A val="<<_val<<endl;
}

//B.cpp
#include "B.h"
#include "A.h"
#include <iostream>

using namespace std;

B::B(double val)
:_val(val)
{
}

void B::SetA(A *a)
{
    _a = a;
    cout<<"Inside SetA()"<<endl;
    _a->Print();
}

void B::Print()
{
    cout<<"Type:B val="<<_val<<endl;
}

//main.cpp
#include "A.h"
#include "B.h"

int main(int argc, char* argv[])
{
    A a(10);
    B b(3.14);
    a.Print();
    a.SetB(&b);
    b.Print();
    b.SetA(&a);
    return 0;
}
100
ответ дан Autodidact 23 November 2019 в 00:45
поделиться

Вещи помнить:

  • Это не будет работать, если class A будет иметь объект class B как участник или наоборот.
  • Предописание является способом пойти.
  • Порядок вопросов объявления (который является, почему Вы выселяете определения).
    • , Если оба класса вызывают функции другого, необходимо выгнать определения с квартиры.

Чтение FAQ:

19
ответ дан Ken Y-N 23 November 2019 в 00:45
поделиться

Я когда-то решил этот вид проблемы путем перемещения всего , встраивает после того, как определение класса и помещение #include для других классов незадолго до эти встраивает в заголовочном файле. Таким образом, каждый удостоверяется, что все definitions+inlines установлены предшествующие, встраивание анализируется.

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

Как это

// File: A.h
#ifndef __A_H__
#define __A_H__
class B;
class A
{
    int _val;
    B *_b;
public:
    A(int val);
    void SetB(B *b);
    void Print();
};

// Including class B for inline usage here 
#include "B.h"

inline A::A(int val) : _val(val)
{
}

inline void A::SetB(B *b)
{
    _b = b;
    _b->Print();
}

inline void A::Print()
{
    cout<<"Type:A val="<<_val<<endl;
}

#endif /* __A_H__ */

... и выполнение того же в B.h

11
ответ дан epatel 23 November 2019 в 00:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: