Newsgroup: it.comp.lang.c++
Titolo: Dichiarazioni incrociate

Ho due classi, Alfa e Beta. Alfa deve saper "conoscere"  Beta e Beta deve
saper "conoscere" Alfa. Ovviamente il compilatore mi da errore. Come si
risolve il problema?
#include <cstdlib>
#include <stdio.h>
class Alfa
{
  public:
    Alfa(int x) {value = x;}
    int value;
    void sumBeta(Beta x) {value += x.value;}
};
class Beta
{
  public:
    Beta(int x) {value = x;}
    int value;
    void sumAlfa(Alfa x) {value += x.value;}
};
int main(int argc, char *argv[])
{
  Alfa alfa(4);
  Beta beta(7);
  beta.sumAlfa(alfa);
  printf("%d\n", alfa.value + beta.value);
  system("PAUSE");
  return 1;
}
MESSAGGI DI ERRORE DEL COMPILATORE:
9 C:\Documenti\Progetti C++\Test vario\main.cpp variable or field `sumBeta'
declared void
9 C:\Documenti\Progetti C++\Test vario\main.cpp expected `;' before '('
token
10 C:\Documenti\Progetti C++\Test vario\main.cpp expected `;' before '}'
token
Kaos.

Non saprei come risolvere ponendo tutto il codice nel main...non l'ho
mai fatto...
Ma usando un file di intestazione e uno di "libreria" non si  hanno
problemi:
-->main.cpp
#include <cstdlib>
#include <stdio.h>
#include "lib.h"
int main(int argc, char *argv[])
{
  Alfa alfa(4);
  Beta beta(7);
  beta.sumAlfa(alfa);
  printf("%d\n", alfa.value + beta.value);
  system("PAUSE");
  return 1;
}
-->lib.cpp
#include <cstdlib>
#include <stdio.h>
#include "lib.h"
void Alfa::sumBeta(Beta x) {value += x.value;}
void Beta::sumAlfa(Alfa x) {value += x.value;}
-->lib.h
class Alfa
{
  public:
    Alfa(int x) {value = x;}
    int value;
    void sumBeta(class Beta x);
};
class Beta
{
  public:
    Beta(int x) {value = x;}
    int value;
    void sumAlfa(Alfa x);
};
Perche' poi usi in cpp le librerie del C invece di usare <iostream> ad
esempio?

 mai fatto...
Si puo' risolvere anche lasciando tutto in un solo file.
Basta usare una forward declaration di "Beta" e spostare la definizione 
di "Alfa::sumBeta" dopo la definizione della classe "Beta".
Alternativamente, si scambia Alfa con Beta.
Ecco la prima soluzione:
#include <cstdlib>
#include <stdio.h>
class Beta;
class Alfa
{
   public:
     Alfa(int x) {value = x;}
     int value;
     void sumBeta(Beta x);
};
class Beta
{
   public:
     Beta(int x) {value = x;}
     int value;
     void sumAlfa(Alfa x) {value += x.value;}
};
inline void Alfa::sumBeta(Beta x) {value += x.value;}
int main(int argc, char *argv[])
{
   Alfa alfa(4);
   Beta beta(7);
   beta.sumAlfa(alfa);
   printf("%d\n", alfa.value + beta.value);
   return 1;
}
-- 
     Carlo Milanesi
 
http://digilander.libero.it/carlmila

Ho testato il codice di Swo_On e funziona correttamente. Quello di Carlo
Milanesi non l'ho provato, ma credo sia corretto.
Ma... ho trovato una soluzione ancora piů felice ingegneristicamente di
quella di Swo_On.
Si puň continuare ad utilizzare due file diversi per le due classi con le
relative intestazioni, quindi Alfa.h, Alfa.cpp, Beta.h e Beta.cpp.
Basta dichiarare le classi usando la parola riservata "class" prima dei
parametri, cosě:
//
// File Alfa.h
//
#ifndef ALFA_H
#define ALFA_H
#include "Beta.h"
class Alfa
{
  public:
    Alfa(int x) {value = x;}
    int value;
    void sumBeta(class Beta x);
};
#endif // ALFA_H
//
// File Beta.h
//
#ifndef BETA_H
#define BETA_H
#include "Alfa.h"
class Beta
{
  public:
    Beta(int x) {value = x;}
    int value;
    void sumAlfa(class Alfa x);
};
#endif // BETA_H
La parolina "class" salva tutti i miei listati e non mi costringe a
modificare il progetto.
Ma adesso sorge un quesito: dovrebbe essere buona abitudine del
programmatore utilizzare sempre la parola chiave class in questo modo, per
evitare di incorrere in intoppi come quello in cui ero cascato?
Kaos.


 evitare di incorrere in intoppi come quello in cui ero cascato?
L'intoppo in cui eri cascato è solo una parte del problema.
Il problema che hai riscontrato è che il programma non compila.
La mutua dipendenza tra le due classi genera anche altri problemi.
Mettiamo il caso che il programmatore abbia la necessità di
aggiungere una classe Gamma simile ad Alfa e Beta.
Seguendo la stessa strategia si aggiungono le dipendenze:
- Alfa da Gamma
- Beta da Gamma
 - Gamma da Alfa
- Gamma da Beta
In pratica questo vuol dire dover scrivere le funzioni:
void Alfa::sumGamma(Gamma x);
void Beta::sumGamma(Gamma x);
void Gamma::sumAlfa(Alfa x);
void Gamma::sumBeta(Beta x);
Cosa accadrebbe se si volessero aggiungere altre dieci classi?
Le dipendenze e le funzioni da scrivere aumenterebbero molto.
Ci sarebbero centodieci funzioni void XX::sumYY(YY x);
Una delle soluzioni che permette di ridurre le dipendenze è
quella di derivare le classi Alfa, Beta, e Gamma da una
classe astratta.
E' una soluzione classica.
#include <cstdlib>
#include <iostream>
class GreekLetter
{
  public:
    virtual int value()const=0;  //-1-//
};
class Alfa : public GreekLetter
{
  public:
    Alfa(int x):value_(x) {}
    int value()const {return value_;}  //-2-//
    void sumLetter(const GreekLetter& x) {value_ += x.value();}
//-3-//
  private:
    int value_;
};
class Beta : public GreekLetter
{
  public:
    Beta(int x):value_(x) {}
    int value()const {return value_;}   //-2-//
    void sumLetter(const GreekLetter& x) {value_ += x.value();}
//-3-//
  private:
    int value_;
};
class Gamma : public GreekLetter
{
  public:
    Gamma(int x):value_(x) {}
    int value()const {return value_;}  //-2-//
    void sumLetter(const GreekLetter& x) {value_ += x.value();} //-3-//
  private:
    int value_;
};
int sumLetters(const GreekLetter& first, const GreekLetter& second)
//-4-//
{
  return (first.value() + second.value());
}
int main()
{
  using std::cout;
  Alfa alfa(4);
  Beta beta(7);
  Gamma gamma(42);
  beta.sumLetter(alfa);
  alfa.sumLetter(gamma);
  cout << "beta + gamma yields: ";
  cout << ( sumLetters(beta, gamma)  ) << "\n";
  system("PAUSE");
  return 1;
}
Questa soluzione è abbastanza flessibile.
Essa permette di scrivere una funzione //-4-// che
non deve essere modificata ogni volta che
il programmatore ha la necessità di aggiungere
una nuova classe derivata da GreekLetter.
Essa permette di aggiungere una nuova classe
derivata da GreekLetter senza dover aggiungere
nuove funzioni ad Alfa e a Beta. La funzione //-3-//
non viene modificata.
Per aggiungere una nuova classe derivata da GreekLetter
il programmatore deve scrivere la funzione //-2-//
per quella classe.
Ogni nuova classe introduce una nuova dipendenza
della nuova classe solo dalla classe base astratta
GreekLetter.
Le classi derivate da GreekLetter sono indipendenti
tra di loro.
Ugo Donelli

 evitare di incorrere in intoppi come quello in cui ero cascato?
In base a quanto mi hanno risposto su comp.lang.c++.moderated in base
allo standard e' una sintassi valida. Personalmente non la userei,
perche' non e' comunemente nota.
Ciao,
Nicola

> Personalmente non la userei, perche' non e' comunemente nota.
Ma funziona!
Kaos.