[C++] Problema di compilazione causato da un namespace

di il
8 risposte

[C++] Problema di compilazione causato da un namespace

Salve, provando a compilare il seguente codice (gcc version 6.3.0 20170516):

// dado.h
#ifndef DADO_H
#define DADO_H

//La classe Dado fa parte dello spazio di nomi definito da Games
namespace Games {
	class Dado;
}

class Games::Dado {
	public:
		Dado(); //COSTRUTTORE
		Dado(int numFacce); //COSTRUTTORE OVERLOADED
		Dado(const Dado& esistente); //COSTRUTTORE DI COPIA
		Dado(Dado&& rvalue);         //COSTRUTTORE DI SPOSTAMENTO
		Dado& operator=(const Dado& esistente); //OVERLOADING OPERATORE DI COPIA DI UN OGGETTO
		Dado& operator=(Dado&& rvalue); //OVERLOADING OPERATORE DI COPIA DI UN RVALUE
		~Dado(); //DISTRUTTORE
		int getFacciaCorrente() const; //METODO const. Inibisce la modifica di qualsiasi membro di classe
		static int getRandom(int max);        //METODO statico
		void lanciaDado();
		int getNumeroFacce() const;
		void setNumeroFacce(int numFacce);
		friend std::ostream& operator<<(std::ostream& out, const Dado& o); 
	private:
		int* p_facciaCorrente;
		int numeroFacce;
};

#endif // DADO_H

// dado.cpp
#include <iostream>
#include "dado.h"
#include <cstdlib>
#include <utility> //PER std::move

//DISTRUTTORE
Games::Dado::~Dado()
{
	delete p_facciaCorrente;
}

//COSTRUTTORE
Games::Dado::Dado()
{
	numeroFacce = 6;
	p_facciaCorrente = new int;
	*p_facciaCorrente = 0; 
}

//COSTRUTTORE OVERLOADED
Games::Dado::Dado(int numFacce)
{
	numeroFacce = numFacce;
	p_facciaCorrente = new int;
        *p_facciaCorrente = 0;
}

//COSTRUTTORE DI COPIA
Games::Dado::Dado(const Dado& esistente)
{
	numeroFacce = esistente.numeroFacce; 
	p_facciaCorrente = new int;
        *p_facciaCorrente = *(esistente.p_facciaCorrente);
}

//OVERLOADING OPERATORE DI UGUALE
Games::Dado& Games::Dado::operator=(const Dado& esistente)
{
        numeroFacce = esistente.numeroFacce;
        p_facciaCorrente = new int;
        *p_facciaCorrente = *(esistente.p_facciaCorrente);
	return *this;
}

//COSTRUTTORE DI SPOSTAMENTO
Games::Dado::Dado(Dado&& rvalue) : numeroFacce(rvalue.numeroFacce)
{
	p_facciaCorrente = (std::move(rvalue.p_facciaCorrente)); //AGGIORNO IL PUNTATORE DEL NUOVO OGGETTO
	rvalue.p_facciaCorrente = nullptr;                       //E CANCELLO QUELLO DEL VECCHIO 
        rvalue.numeroFacce = 0; 
}

//OVERLOADING OPERATORE DI COPIA DI UN RVALUE
Games::Dado& Games::Dado::operator=(Dado&& rvalue)
{
	numeroFacce = rvalue.numeroFacce;
	p_facciaCorrente = (std::move(rvalue.p_facciaCorrente)); //AGGIORNO IL PUNTATORE DEL NUOVO OGGETTO
        rvalue.p_facciaCorrente = nullptr;                       //E CANCELLO QUELLO DEL VECCHIO
        rvalue.numeroFacce = 0;
}

int Games::Dado::getFacciaCorrente() const //METODO const. Inibisce la modifica di qualsiasi membro di classe
{
	return *p_facciaCorrente;
}

int Games::Dado::getRandom(int max)        //METODO definito statico nello header file
{
	return (rand() % max + 1);
}

void Games::Dado::lanciaDado()
{
	*p_facciaCorrente = getRandom(getNumeroFacce());
}

int Games::Dado::getNumeroFacce() const
{
	return numeroFacce;
}

void Games::Dado::setNumeroFacce(int numFacce)
{
	numeroFacce = numFacce;
}

std::ostream& operator<<(std::ostream& out, const Games::Dado& p)    
{                                                                    
    return out << "la faccia corrente e: " << p.getFacciaCorrente();
}

//main.cpp
#include <iostream>
#include "dado.h"

using Games::Dado;
using namespace std;

int main ()
{
	Dado d(10);
	d.lanciaDado();
	
	//UTILIZZO LA FUNZIONE FRIEND CHE FA LO OVERLOAD DELLO OPERATORE <<
	std::cout << d << endl;

	return 0;

}
ottengo questo errore:

/tmp/ccWSVmS6.o: nella funzione "main":
main.cpp:(.text+0x34): riferimento non definito a "Games::operator<<(std::ostream&, Games::Dado const&)"
collect2: error: ld returned 1 exit status


Se invece tolgo la classe Dado da dentro il namespace chiamato Games riesco a compilarlo perfettamente.
Qualcuno sa dirmi cosa non va nell'utilizzo del namespace?

grazie

8 Risposte

  • Re: [C++] Problema di compilazione causato da un namespace

    
    Qualcuno sa dirmi cosa non va nell'utilizzo del namespace?
    
    Che non lo usi nella dichiarazione della funzione friend. Le funzioni friend sono di fatto delle funzioni libere, per cui il namespace va specificato.
    Tu lo inserisci nella definizione della friend, ma non nella dichiarazione (nel corpo della classe Dado), per cui il linker da errore.
    
          int getNumeroFacce() const;
          void setNumeroFacce(int numFacce);
          friend std::ostream& operator<<(std::ostream& out, const Games::Dado& o);
       private:
    
    P.S.
    Perché usi un puntatore per un int solo?
  • Re: [C++] Problema di compilazione causato da un namespace

    Ciao Shodan, grazie della risposta, ho modificato la dichiarazione della funzione friend in dado.h come mi hai detto:
    
    friend std::ostream& operator<<(std::ostream& out, const Games::Dado& o);
    
    ma continua a darmi lo stesso errore di prima, ho dimenticato qualocosa?

    PS: quel puntatore a int era solo una prova a scopo didattico
  • Re: [C++] Problema di compilazione causato da un namespace

    Cambia anche:
    
    std::ostream& Games::operator<<(std::ostream& out, const Games::Dado& p)   
    {                                                                   
        return out << "la faccia corrente e: " << p.getFacciaCorrente();
    }
    
    Dato che la funzione friend viene dichiarata appartenente a Games (anche se nel corpo della classe), anche la definizione dev'essere innestata nel namespace altrimenti il compilatore vede ambiguo l'operatore <<
  • Re: [C++] Problema di compilazione causato da un namespace

    Con questa modifica mi da questo altro messaggio di errore:

    dado.cpp:88:15: warning: ‘std::ostream& Games::operator<<(std::ostream&, const Games::Dado&)’ has not been declared within Games
    std::ostream& Games::operator<<(std::ostream& out, const Games::Dado& p)
    ~~~~~~~~~~~~~^
    In file included from dado.cpp:3:0:
    dado.h:24:24: note: only here as a friend
    friend std::ostream& operator<<(std::ostream& out, const Games::Dado& o);
    ~~~~~~~~~~~~~~~~~~^
  • Re: [C++] Problema di compilazione causato da un namespace

    Non è un errore, ma uno warning. Il codice compila (testato con Gcc e VCpp) e funziona, ma se vuoi evitare lo warning hai due strade:
    La prima è:
    
    namespace Games {
    	class Dado;
    	std::ostream& operator<<(std::ostream& out, const Dado& o);
    }
    ...
    std::ostream& Games::operator<<(std::ostream& out, const Games::Dado& p) {
    	return out << "la faccia corrente e: " << p.getFacciaCorrente();
    }
    
    La seconda è semplicemente:
    
    
    namespace Games {	
    	std::ostream& operator<<(std::ostream& out, const Dado& p) {
    		return out << "la faccia corrente e: " << p.getFacciaCorrente();
    	}
    }
    
    In ambedue i casi l'operatore deve essere inserito all'interno del namespace.
  • Re: [C++] Problema di compilazione causato da un namespace

    Grazie shodan, in effetti le due strade che hai proposto fanno compilare il codice, però in entrambe hai tolto il "friend", ed in effetti ad esempio nella prima strada da te indicata se si dichiara la funzione come friend dentro il namespace continua a dare errore di compilazione. Per quale motivo non si può associare esplicitamente una funzione friend ad un namespace?
  • Re: [C++] Problema di compilazione causato da un namespace

    Non ho tolto nessun "friend", ho solo messo la dichiarazione della funzione all'interno del namespace.
    Infatti se modifico e scrivo:
    
    std::ostream& Games::operator<<(std::ostream& out, const Games::Dado& p) {
    	return out << "la faccia corrente e': " << *p.p_facciaCorrente; // accesso diretto al membro private
    }
    
    compila senza problemi.
    Per quale motivo non si può associare esplicitamente una funzione friend ad un namespace?
    Perché la funzione friend deve risiedere dentro il namespace altrimenti la chiamata è ambigua se nel namespace generale esiste un'altra funzione con lo stesso prototipo.
  • Re: [C++] Problema di compilazione causato da un namespace

    Ok avevo erroneamente spostato la dichiarazione della funzione friend dentro il namespace togliendola da dentro la classe, invece adesso le ho lasciate entrambe e compila senza warning
    
    // dado.h
    #ifndef DADO_H
    #define DADO_H
    
    //La classe Dado fa parte dello spazio di nomi definito da Games
    namespace Games {
            class Dado;
            std::ostream& operator<<(std::ostream& out, const Dado& o);
    }
    
    class Games::Dado {
            public:
                    Dado(); //COSTRUTTORE
                    Dado(int numFacce); //COSTRUTTORE OVERLOADED
                    Dado(const Dado& esistente); //COSTRUTTORE DI COPIA
                    Dado(Dado&& rvalue);         //COSTRUTTORE DI SPOSTAMENTO
                    Dado& operator=(const Dado& esistente); //OVERLOADING OPERATORE DI COPIA DI UN OGGETTO
                    Dado& operator=(Dado&& rvalue); //OVERLOADING OPERATORE DI COPIA DI UN RVALUE
                    ~Dado(); //DISTRUTTORE
                    int getFacciaCorrente() const; //METODO const. Inibisce la modifica di qualsiasi membro di classe
                    static int getRandom(int max);        //METODO statico
                    void lanciaDado();
                    int getNumeroFacce() const;
                    void setNumeroFacce(int numFacce);
                    friend std::ostream& operator<<(std::ostream& out, const Games::Dado& o); //public, prot o private non hanno effetto sui friend
                    virtual std::string getColore() const { return ""; }; //metodo virtuale. Ha una implementazione di base per la classe
                                                                          //madre, che le classi figlie overriddano
            protected:
                    int* p_facciaCorrente;
            private:
                    int numeroFacce;
    };
    
    #endif // DADO_H
    
    Grazie mille!
Devi accedere o registrarti per scrivere nel forum
8 risposte