Dostęp do danych między klasami.

0

Witam

Na początek kod programu, który ma łatwiej zobrazować moje pytanie:

/*
  testowanie klas
*/
#include <iostream>
using namespace std;
//
// predeklaracja / deklaracja wstępna
class DANE; // -->> błąd forward declaration of `struct DANE' 
//
class FUNKCJE
{
  public:
    FUNKCJE( );
    int celKopiowania;
    DANE *pDane;
    void inicjalizacja(DANE *pDaneTemp);
    void kopiowanie( );
};
FUNKCJE::FUNKCJE( )
{
  celKopiowania = 80;
}
void FUNKCJE::inicjalizacja(DANE *pDaneTemp)
{
  pDane = pDaneTemp;
};
void FUNKCJE::kopiowanie( )
{
  celKopiowania = pDane->zrodloKopiowania; // -->> błąd invalid use of undefined type 'struct DANE'
};
//
class DANE
{
  public:
    DANE( );
    int zrodloKopiowania;
    FUNKCJE f;
};
DANE::DANE( )
{
  zrodloKopiowania = 20;
}
//
//  główny program
int main()
{
  static DANE d;
  d.f.inicjalizacja(&d);
//
  cout << " \n Przed kopiowaniem: \n";
  cout << " \tZrodlo:\t" << d.zrodloKopiowania << "\n";
  cout << " \tCel:\t" << d.f.celKopiowania << "\n";
//
// KOPIOWANIE
  d.f.kopiowanie( );
//
  cout << " \n po kopiowaniu: \n";
  cout << " \tZrodlo:\t" << d.zrodloKopiowania << "\n";
  cout << " \tCel:\t" << d.f.celKopiowania << "\n";
//
  cout << " \n Koniec programu. Nacisnij ENTER aby zamknac okno. \n";
  getchar();
  return 0;
}

Chciałbym mieć dostęp do danych klasy "d" (klasa nadrzędna) z klasy "f". Przekazuję wskaźnik na klasę "d" do klasy "f" podczas wywołania funkcji inicjalizacja. Póki nie wpiszę linii celKopiowania = pDane->zrodloKopiowania;

Wtedy dostaję dwa błędy odpowiednio wykomentowane w kodzie źródłowym:

  1. invalid use of undefined type `struct DANE'
  2. forward declaration of `struct DANE'.

Czy w ogóle jest to jakoś możliwe do zrobienia? Proszę o pomoc.

Grzesiek.

1

Można przyjąć, że kompilator "idzie" po kodzie od góry do dołu. Na początku widzi, że istnieje taka klasa jak Dane. Następnie widzi definicję klasy funkcja, z funkcją pobierającą wskaźnik na DANE, wszystko OK, bo wie że taka klasa istnieje. Następnie jest min. definicja tej funkcji pobierającej wskaźnik na obiekt klasy Dane, mimo to, że kompilator wie o istnieniu tej klasy, to nie może jej użyć bez definicji. Dopiero później jest definicja klasy Dane. Ta definicja potrzebuje tylko zdefiniowanej klasy Funkcja, definicje metod są na tym etapie niepotrzebne.

0

Kompilator C++ przetwarza klasy dwufazowo: najpierw deklaracje klas z deklaracjami metod, a potem (w drugiej fazie) przetwarza definicje. Stąd ten błąd. Żeby to rozwiązać, należy pisać klasy C++ po bożemu, czyli deklaracje klas i metod w plikach nagłówkowych *.h z wartownikiem typu "#ifndef NAZWAKLASY_H #define NAZWAKLASY_H #endif", a definicje w plikach źródłowych *.cpp.

0

Dzięki za szybkie odpowiedzi.

Wyjaśnienie kolegi Zjarek przemawia do mnie jaśniej. Przestawienie implementacji clasy w inną kolejność rozwiązuje mój problem poniżej listing.

/*
  testowanie klas
*/
#include <iostream>
using namespace std;
//
// predeklaracja / deklaracja wstępna
class DANE;
//
// definicja klasy FUNKCJE
class FUNKCJE
{
  public:
    FUNKCJE( );
    int celKopiowania;
    DANE *pDane;
    void inicjalizacja(DANE *pDaneTemp);
    void kopiowanie( );
};
//
// cała klasa DANE
class DANE
{
  public:
    DANE( );
    int zrodloKopiowania;
    FUNKCJE f;
};
DANE::DANE( )
{
  zrodloKopiowania = 20;
}
//
// implementacja klasy FUNKCJE
FUNKCJE::FUNKCJE( )
{
  celKopiowania = 80;
}
void FUNKCJE::inicjalizacja(DANE *pDaneTemp)
{
  pDane = pDaneTemp;
};
void FUNKCJE::kopiowanie( )
{
  celKopiowania = pDane->zrodloKopiowania;
};
//
//  główny program
int main()
{
  static DANE d;
  d.f.inicjalizacja(&d);
//
  cout << " \n Przed kopiowaniem: \n";
  cout << " \tZrodlo:\t" << d.zrodloKopiowania << "\n";
  cout << " \tCel:\t" << d.f.celKopiowania << "\n";
//
// KOPIOWANIE
  d.f.kopiowanie( );
//
  cout << " \n po kopiowaniu: \n";
  cout << " \tZrodlo:\t" << d.zrodloKopiowania << "\n";
  cout << " \tCel:\t" << d.f.celKopiowania << "\n";
//
  cout << " \n Koniec programu. Nacisnij ENTER aby zamknac okno. \n";
  getchar();
  return 0;
}

Natomiast nie wiem jak miałbym to przedstawić wraz z plikami dodatkowymi. Wykorzystuję to w większym programie właśnie z podziałem na pliki nagłówkowe i w tej chwili pojawia się następne pytanie jak to ma być, załączam kody plików. Wygodniej zrozumieć na prostym przykładzie stąd ten tu przytaczany.


// plik main.cpp

/*
  testowanie klas wersja z plikami nagłówkowymi
*/
#include <iostream>
using namespace std;
//
// predeklaracja / deklaracja wstępna
class DANE;
//
// załączane pliki
#include "funkcje.hpp"
#include "dane.hpp"
//
//  główny program
int main()
{
  static DANE d;
  d.f.inicjalizacja(&d);
//
  cout << " \n Przed kopiowaniem: \n";
  cout << " \tZrodlo:\t" << d.zrodloKopiowania << "\n";
  cout << " \tCel:\t" << d.f.celKopiowania << "\n";
//
// KOPIOWANIE
  d.f.kopiowanie( );
//
  cout << " \n po kopiowaniu: \n";
  cout << " \tZrodlo:\t" << d.zrodloKopiowania << "\n";
  cout << " \tCel:\t" << d.f.celKopiowania << "\n";
//
  cout << " \n Koniec programu. Nacisnij ENTER aby zamknac okno. \n";
  getchar();
  return 0;
}


// plik dane.hpp

#ifndef dane_hpp
#define dane_hpp
//
// definicja klasy DANE
class DANE
{
  public:
    DANE( );
    int zrodloKopiowania;
    FUNKCJE f; // -->> błąd `FUNKCJE' does not name a type
};
#endif


// plik dane.cpp

#include "dane.hpp"
//
// implementacja klasy DANE
DANE::DANE( )
{
  zrodloKopiowania = 20;
}


// plik funkcje.hpp

#ifndef funkcje_hpp
#define funkcje_hpp
//
// definicja klasy FUNKCJE
class FUNKCJE
{
  public:
    FUNKCJE( );
    int celKopiowania;
    DANE *pDane;
    void inicjalizacja(DANE *pDaneTemp);
    void kopiowanie( );
};
#endif


// plik funkcje.cpp

#include "funkcje.hpp"
//
// implementacja klasy FUNKCJE
FUNKCJE::FUNKCJE( )
{
  celKopiowania = 80;
}
void FUNKCJE::inicjalizacja(DANE *pDaneTemp)
{
  pDane = pDaneTemp;
};
void FUNKCJE::kopiowanie( )
{
  celKopiowania = pDane->zrodloKopiowania;
};

W pliku dane.hpp pojawia się błąd - jest tam zaznaczony. Z tym dołączaniem plików zawsze miałem kłopot, ale zawsze dochodziłem w końcu do ładu.
Liczę na Ciebie Zjarek :)
Może przy okazji nie wiem jak mam rozdzielić definicję od implementacji sporo (zapewne) nie kumam do końca dołączania plików :(, bo nie wiem w którym momencie sprawdzane/dołączane są pliki typu *.cpp
Być może użytkownik norma teraz mnie przekona.

Grzesiek

0

// plik main.cpp
 
/*
  testowanie klas wersja z plikami nagłówkowymi
*/
#include <iostream>
using namespace std;

//
// załączane pliki
#include "dane.h"
//
//  główny program
int main()
{
  static DANE d;
  d.f.inicjalizacja(&d);
//
  cout << " \n Przed kopiowaniem: \n";
  cout << " \tZrodlo:\t" << d.zrodloKopiowania << "\n";
  cout << " \tCel:\t" << d.f.celKopiowania << "\n";
//
// KOPIOWANIE
  d.f.kopiowanie( );
//
  cout << " \n po kopiowaniu: \n";
  cout << " \tZrodlo:\t" << d.zrodloKopiowania << "\n";
  cout << " \tCel:\t" << d.f.celKopiowania << "\n";
//
  cout << " \n Koniec programu. Nacisnij ENTER aby zamknac okno. \n";
  getchar();
  return 0;
}
 
 
// plik dane.h
 
#ifndef DANE_H
#define DANE_H

#include "funkcje.h" //potrzebne do FUNKCJE poniżej.
//
// definicja klasy DANE
class DANE
{
  public:
    DANE( );
    int zrodloKopiowania;
    FUNKCJE f;
};
#endif
 
 
// plik dane.cpp
 
#include "dane.h"
//
// implementacja klasy DANE
DANE::DANE( )
{
  zrodloKopiowania = 20;
}
 
 
// plik funkcje.h
 
#ifndef FUNKCJE_H
#define FUNKCJE_H

#include "dane.h" //potrzebne do DANE poniżej
//
// definicja klasy FUNKCJE
class FUNKCJE
{
  public:
    FUNKCJE( );
    int celKopiowania;
    DANE *pDane;
    void inicjalizacja(DANE *pDaneTemp);
    void kopiowanie( );
};
#endif
 
 
// plik funkcje.cpp
 
#include "funkcje.h"
//
// implementacja klasy FUNKCJE
FUNKCJE::FUNKCJE( )
{
  celKopiowania = 80;
}
void FUNKCJE::inicjalizacja(DANE *pDaneTemp)
{
  pDane = pDaneTemp;
};
void FUNKCJE::kopiowanie( )
{
  celKopiowania = pDane->zrodloKopiowania;
};

Można zauważyć w listingach, że te "include" powtarzają się dla pewnych plików. To nie przeszkadza ze względu na istnienie odpowiednich "ifndef" (które pilnują, by nie było bałaganu).

0

Po wpisaniu twojego kodu niestety roi się od błędów po kompilacji. Jedyna różnica to to że mam pliki nagłówkowe .hpp i odwołania do nich oczywiście poprawne.

Poniżej błędy jakie wyskoczyły.

15 dane.hpp:7, from main.cpp In file included from dane.hpp:7, from main.cpp
15 main.cpp from main.cpp
15 funkcje.hpp ISO C++ forbids declaration of DANE' with no type 15 funkcje.hpp expected ;' before '*' token
16 funkcje.hpp variable or field inicjalizacja' declared void 16 funkcje.hpp expected ;' before '(' token
main.cpp In function `int main()':
21 main.cpp 'class FUNKCJE' has no member named 'inicjalizacja'

15 linia w main to: #include "dane.hpp"
15 linia w funkcje to: DANE *pDane;
16 linia w funkcje to: void inicjalizacja(DANE *pDaneTemp);

W ogóle nie kumam o co chodzi, ale ilość błędów mówi mi że to droga w złą stronę, ale nie raz jest tak, że 1 poprawka powoduje że działa już dobrze.
Wieczorem spróbuję

0

W ogóle cóż to za chore klasy? Do kopiowania/przechowywania danych użyj kontenerów i funkcji STL.

0

adf88 być może moja wiedza nie jest imponująca, może jest nawet mizerna, ale mam jakieś pomysły i staram się je wykonać. Jak już wcześniej napisałem chodzi o zobrazowanie problemu który mam w większym projekcie a zamieszczanie go w całości jest bezcelowe. Dodam tylko, że po prostu potrzebuję mieć klasę bazową z danymi, do której będą miały dostęp wszelkie podklasy z różnymi procedurami funkcjonalnymi.
Pytam na poziomie swojej wiedzy, nie znam bibliotek STL i jeszcze nie "przerabiałem" kontenerów. Twoja wypowiedź że są to jakieś chore klasy w ogóle nie jest pomocna, skoro nie chcesz pomóc to po prostu nie odpowiadaj w temacie - z całym szacunkiem dla twojej reputacji.

Grzesiek

0
gotik napisał(a):

Jak już wcześniej napisałem chodzi o zobrazowanie problemu który mam w większym projekcie
Napisałeś? Nie zauważyłem. Mam nadzieję, że w tym większym projekcie klasy nie nazywają się "dane" i "funkcje".

gotik napisał(a):

nie znam bibliotek STL i jeszcze nie "przerabiałem" kontenerów.
To jak najszybciej poznaj. To jest istota C++. Pewne rzeczy już napisano i są dostępne z poziomu biblioteki standardowej i należy z nich korzystać. Tak jak pisałem - przechowywanie danych (układania ich w listy/tablice/mapy) czy algorytmy organizujące przechowywanie (przenoszenie, łączenie, rozdzielanie, sortowanie, wyszukiwanie, ...) to właśnie STL.

Twoje klasy wyglądają trochę jakby miały właśnie organizować przechowywanie danych (jakieś dane, kopiowanie...) dlatego sugeruję zainteresowanie się STL'em. Nie chcesz skorzystać z mojej rady, trudno. Ale myśl, że nie chce pomóc, a wytknąć niewiedzę, wręcz przeciwnie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1