Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Przekazywanie obiektowi referencji do nieistniejącego obiektu

Ostatnio zmodyfikowano 2016-10-02 13:17
Autor Wiadomość
marianexyx
Temat założony przez niniejszego użytkownika
Przekazywanie obiektowi referencji do nieistniejącego obiektu
» 2016-10-01 10:14:48
Zamieniam kod moich aplikacji na obiektowy, gdzie przy okazji uczę się jak to robić, bo nigdy wcześniej nie wchodziłem głębiej w OOP. Na pewnym etapie pisania pojawiła mi się potrzeba przekazania nowo tworzonemu obiektowi referencji do obiektu, który jeszcze nie istnieje. Nie mogę zamienić kolejności tworzenia tych obiektów, bo drugi tak samo chce zawierać ten pierwszy w swym konstruktorze.

C/C++
class B;

class A
{
private:
    B * _pB;
   
public:
    A( B * pB ) { _pB = pB }
}

class B
{
private:
    A * _pA;
   
public:
    B( A * pA ) { _pA = pA }
}

A obiektA( & obiektB );
B obiektB( & obiektA );

Dostaję oczywisty błąd:
error: 'obiektB' was not declared in this scope

Jak mogę zatem przekazać obiektowi referencję do innego obiektu, który w powyższej formie nie mógłby być zadeklarowany wcześniej?
P-152139
jankowalski25
» 2016-10-01 11:26:41
1. Dokładasz domyślny konstruktor, gdzie ustawiasz wskaźnik na zero.
2. Tworzysz pierwszy obiekt domyślnym konstruktorem.
3. Tworzysz drugi obiekt przekazując pierwszy jako argument.
4. Tworzysz trzeci obiekt przekazując drugi jako argument.
5. Pozbywasz się pierwszego obiektu.
6. Zapewniasz, że obiekt drugi i trzeci są poprawnie utworzone (likwidujesz skutki uboczne użycia pierwszego obiektu, jeśli takie występują).

Dopisano:
A nie wystarczy przekazać pustego wskaźnika do konstruktora?
P-152142
michal11
» 2016-10-01 15:10:33
Nie wiem co robisz ale najprawdopodobniej robisz to źle, stworzyłeś cykliczne zależności a to oznacza, że masz coś źle zaprojektowane. Pokaż jakiś konkretniejszy kod.
P-152152
marianexyx
Temat założony przez niniejszego użytkownika
» 2016-10-01 18:34:04
Starałem się okroić kod z większości zbędnych elementów przy tym zagadnieniu.

komunikacja.h - klasa która na życzenie użytkownika wyrzuca informacje o stanie systemu, oraz odpowiada za przepływ informacji po aplikacji, jak i poza nią

C/C++
#ifndef komunikacja_h
#define komunikacja_h

class cServoA;
class cServoB;
class cServoC;
class cServoD;
class cSilnik;
class cRamie;

class cKomunikacja
{
private:
    bool _bPokazujeInfo; // jeżeli = true, to wypluwa na serial port tonę informacji o swoim stanie
    cServoA * _pServoA;
    cServoB * _pServoB;
    cServoC * _pServoC;
    cServoD * _pServoD;
    cServoEF * _pSilnikE;
    cServoEF * _pSilnikF;
    cRamie * _pRamie;
   
public:
    cKomunikacja( cServoA * pServoA, cServoB * pServoB, cServoC * pServoC, cServoD * pServoD, cSilnik * pServoE, cSilnik * pServoF, cRamie * pRamie );
   
    void PokazPozycjeRamienia();
    void PrzygotujOdpowiedzNaRdzen( String sPolecenieRdzenia );
};

#endif



komunikacja.cpp

C/C++
#include "komunikacja.h"

cKomunikacja::cKomunikacja( cServoA * pServoA, cServoB * pServoB, cServoC * pServoC, cServoD * pServoD, cServoEF * pServoEF, cRamie * pRamie )
{
    _bPokazujeInfo = false;
   
    _pServoA = pServoA;
    _pServoB = pServoB;
    _pServoC = pServoC;
    _pServoD = pServoD;
    _pSilnikE = pServoE;
    _pSilnikF = pServoF;
    _pRamie = pRamie;
}

void cKomunikacja::PokazPozycjeRamienia()
{
    if( _bPokazujeInfo == true )
    {
        Serial.print( "kp = " ); Serial.print( _pServoA.getKat() );
        Serial.print( ", alpha= " ); Serial.print( _pServoB.getKat() );
        Serial.print( ", beta= " ); Serial.print( _pServoC.getKat() ); if(( int ) _pServoC.getKat() >= 157 ) Serial.print( "!!!" );
       
        Serial.print( ", fi= " ); Serial.println( _pServoD.getKat() );
        Serial.print( " | y = " ); Serial.print( _pRamie.getYtemp() );
        Serial.print( ", z = " ); Serial.print( _pRamie.getZtemp() );
        Serial.print( ", z_upgr = " ); Serial.print( _pRamie.getZtemp() ); if(( int ) dZmiennaDoPokazania >= 236 ) Serial.print( "!!!" );
       
    }
}

void cKomunikacja::PrzygotujOdpowiedzNaRdzen( String sPolecenieRdzenia )
{
    /*(...)*/
}



servo_a.h - jedna z kilku tego typu podobnych do siebie klas

C/C++
#ifndef servo_a_h
#define servo_a_h

#include "silnik.h"
#include "komunikacja.h"

class cServoA
    : public cSilnik
{
private: //pola przypisywane do parametrów z konstruktora są dziedziczone
   
public:
    cServoA( /*(...)*/ cKomunikacja * pKomunikacja )
    {
        _pKomunikacja = pKomunikacja;
    }
   
    String Trash()
    {
        _pKomunikacja->PrzygotujOdpowiedzNaRdzen( "r_trash" );
        String sXYprzyResecie = "(170,240)";
        return sXYprzyResecie;
    }
};

#endif

main.cpp - tutaj tworzę obiekty klas cServo, które mają możliwość w niektórych miejscach używać metod klasy cKomunikacja, która zajmuje się wymianą informacji pomiędzy elementami systemu (np. metodą PrzygotujOdpowiedzNaRdzen() ). Z drugiej strony chcę w obiekcie klasy cKomunikacja używać wartości z pól obiektów klasy cServo, m.in. do wyświetlania stanu wszystkich Servo (cKomunikacja::PokazPozycjeRamienia) na zawołanie w np. pliku main.cpp

C/C++
#include "silnik.h"
#include "komunikacja.h"
#include "ramie.h"
#include "servo_a.h"
#include "servo_b.h"
#include "servo_c.h"
#include "servo_d.h"
#include "servo_ef.h"

cServoA ServoA_kp( 2, "kp", 15, 175, & LCD_angle, & LCD_pos, & Komunikaty );
cServoB ServoB_alpha( 3, "alpha", 0, 180, & LCD_angle, & LCD_pos );
cServoC ServoC_beta( 4, "beta", 24, 157, & LCD_angle, & LCD_pos );
cServoD ServoD_fi( 5, "fi", 45, 180, & LCD_angle, & LCD_pos, & Komunikaty );
cServoEF ServoE_ks1( 6, "ks1", 82, 131, & LCD_angle, & LCD_pos, & Komunikaty );
cServoEF ServoF_ks2( 7, "ks2", 200 - 131, 200 - 82, & LCD_angle, & LCD_pos );

cKomunikacja Komunikaty( & ServoA_kp, & ServoB_alpha, & ServoC_beta, & ServoD_fi, & ServoE_ks1, & ServoF_ks2, & Ramie );

/*(...)*/

No i w powyższym przykładzie mam owe referencje do obiektów, które jeszcze nie istnieją.
W razie czego wrzucam jeszcze mój aktualny cały kod: https://github.com/marianexyx​/arduino_chess_control/tree​/master/kinematyka_odwrotna
P-152157
carlosmay
» 2016-10-01 21:30:35
Klasa cKomunikacja ma więcej niż jedną odpowiedzialność. Odpowiada za komunikację i wyświetla dane o systemie.
To powinny być dwie klasy. Prawdopodobnie rozwiąże to problem z używaniem klas na krzyż.

Unikaj zależności cyklicznych, klasa B zna klasę A, to klasa A nie zna klasy B. Jeśli musisz mieć taką zależność
tworzysz klasę C implementującą interfejs odpowiadający potrzebom.
P-152170
marianexyx
Temat założony przez niniejszego użytkownika
» 2016-10-02 13:17:30
@carlosmay: Miałem przez chwilę taką myśl i jak się nad tym zastanowiłem teraz przy kodzie, to rzeczywiście będzie tak jak mówisz i tak zatem zrobię. Dzięki za radę.
P-152177
« 1 »
  Strona 1 z 1