Problem mit #include



  • Hey Leute,
    ich hab ein Projekt mit einigen Headerdateien und den dazugehörigen Sourcedateien.
    Ist es üblich die Klassen einer Vererbungshierachie in eine Header zu stecken und eine Source?
    Denn ich habe das jetzt aufgeteilt, und durch includieren entstehen lauter Fehler.

    Danke schonmal

    Gruß freeG



  • Eigentlich ist es üblich header und source zu trennen, ja.

    Vll solltest du mal die ersten paar Compiler-Fehler posten und die dazugehörigen Zeilen (vll noch 5-10 davor), denn hell sehen kann hier niemand

    bb



  • unskilled schrieb:

    denn hell sehen kann hier niemand

    Ich versuchs dennoch mal.

    @fr33g
    Hast du zyklische Abhängigkeiten gebaut?



  • Also hab mir das mal durchgelesen bekomms aber net hin.

    Aber dass man Definition und Implementierung in Header und Source aufteilt ist mir auch klar, meine Frage war diese, ich habe ja ne Basisklasse, so und dann einige Klassen die von ihr erben, so ich habe dann erst jede Klasse in ne eigene Header-Datei gesetzt, wollte wissen ob es schlauer ist vll alle Klassen in eine Header-Datei und eine Source-Datei zu setzten?

    Hab hier mal den Code, hab einiges mit den includes probiert, vll kann mir jemand kurz helfen wie es klappen könnte.

    Post hier mal die aktuelle "Version" die auch nicht funktionier:

    Query_base.h

    #ifndef QUERY_BASE_H
    #define QUERY_BASE_H
    
    #include <iostream>
    #include "TextQuery.h"
    
    class Query;
    
    class Query_base
    {
    	friend class Query;
    
    	protected:
    		typedef TextQuery::line_no line_no;
    		virtual ~Query_base() {}
    
    	private:
    		virtual std::set< line_no > eval( const TextQuery& )  const = 0;
    		virtual std::ostream& display( std::ostream& = std::cout ) const = 0;
    };
    
    class NotQuery : public Query_base
    {
    	friend Query operator~( const Query& );
    	NotQuery( Query q );
    	std::set< line_no > eval( const TextQuery& ) const;
    	std::ostream& display( std::ostream& ) const;
    	const Query query;
    };
    
    class WordQuery : public Query_base
    {
    	friend class Query;
    	WordQuery( const std::string& s );
    	std::set< line_no > eval( const TextQuery& ) const;
    	std::ostream& display( std::ostream& ) const;
    	std::string query_word;
    };
    
    class BinaryQuery : public Query_base
    {
    	protected:
    		BinaryQuery( Query left, Query right, std::string op );
    		std::ostream& display( std::ostream& ) const;
    		const Query lhs, rhs;
    		const std::string oper;
    };
    
    class AndQuery : public BinaryQuery
    {
    	friend Query operator&( const Query&, const Query& );
    	AndQuery( Query left, Query right );
    	std::set< line_no > eval( const TextQuery& ) const;
    };
    
    class OrQuery : public BinaryQuery
    {
    	friend Query operator|( const Query&, const Query& );
    	OrQuery( Query left, Query right );
    	std::set< line_no > eval( const TextQuery& ) const;
    };
    
    #endif
    

    Query_base.cpp

    #include "Query_base.h"
    #include <set>
    #include <algorithm>
    #include <iterator>
    #include "Query.h"
    
    using namespace std;
    
    NotQuery::NotQuery( Query q ):
    	query( q )
    	{
    	}
    
    set< Query_base::line_no > NotQuery::eval( const TextQuery& file ) const
    {
    	set< line_no > has_val = query.eval( file );
    	set< line_no > ret_lines;
    	for( line_no n = 0; n != file.size(); ++n )
    	{
    		if( has_val.find( n ) == has_val.end() )
    			ret_lines.insert( n );
    	}
    	return ret_lines;
    }
    
    ostream& NotQuery::display( ostream& os ) const
    {
    	return os << "~(" << query << ")";
    } 
    
    WordQuery::WordQuery( const string& s ):
    	query_word( s )
    	{
    	}
    
    set< TextQuery::line_no > WordQuery::eval( const TextQuery& t ) const
    {
    	return t.run_query( query_word );
    }
    
    ostream& WordQuery::display( ostream& os ) const
    {
    	return os << query_word;
    }
    
    BinaryQuery::BinaryQuery( Query left, Query right, string op ):
    	lhs( left ), rhs( right ), oper( op )
    	{
    	}
    
    ostream& BinaryQuery::display( ostream& os ) const
    {
    	return os << "(" << lhs << " " << oper << " " << rhs << ")";
    }
    
    AndQuery::AndQuery( Query left, Query right ):
    	BinaryQuery( left, right, "&" )
    	{
    	}
    
    set< Query_base::line_no > AndQuery::eval( const TextQuery& file ) const
    {
    	set< line_no > left = lhs.eval( file ),
    				  right = rhs.eval( file );
    
    	set< line_no > ret_lines;
    
    	set_intersection( left.begin(), left.end(), right.begin(), right.end(), inserter( ret_lines, ret_lines.begin() ) );
    	return ret_lines;
    }
    
    OrQuery::OrQuery( Query left, Query right ):
    	BinaryQuery( left, right, "|" )
    	{
    	}
    
    set< Query_base::line_no > OrQuery::eval( const TextQuery& file ) const
    {
    	set< line_no > right = rhs.eval( file ),
    			   ret_lines = lhs.eval( file );
    
    	ret_lines.insert( right.begin(), right.end() );
    	return ret_lines;
    }
    

    Query.h

    #ifndef QUERY_H
    #define QUERY_H
    
    #include <set>
    #include "TextQuery.h"
    
    class Query_base;
    class WordQuery;
    class OrQuery;
    class AndQuery;
    class BinaryQuery;
    
    class Query
    {
    	friend Query operator~( const Query& );
    	friend Query operator|( const Query&, const Query& );
    	friend Query operator&( const Query&, const Query& );
    
    	public:
    		Query( const std::string& );
    		Query( const Query& );
    		~Query();
    		Query& operator=( const Query& );
    		std::set< Query_base::line_no > eval( const TextQuery& ) const;
    		std::ostream& display( std::ostream& os ) const;
    
    	private:
    		Query( Query_base* query );
    		Query_base* q;
    		std::size_t* use;
    		void decr_use();
    };
    
    inline Query operator&( const Query& lhs, const Query& rhs )
    {
    	return new AndQuery( lhs, rhs );
    }
    
    inline Query operator|( const Query& lhs, const Query& rhs )
    {
    	return new OrQuery( lhs, rhs );
    }
    
    inline Query operator~( const Query& oper )
    {
    	return new NotQuery( oper );
    }
    
    inline std::ostream& operator<<( std::ostream& os, const Query& q )
    {
    	return q.display( os );
    }
    
    #endif
    

    Query.cpp

    #include "Query.h"
    #include "Query_base.h"
    
    using namespace std;
    
    Query::Query( const string& s ):
    	q( new WordQuery( s ) ), use( new size_t( 1 ) )
    	{
    	}
    
    Query::Query( const Query& orig ):
    	q( orig.q ), use( orig.use )
    	{
    		++*use;
    	}
    
    Query::Query( Query_base* query ):
    	q( query ), use( new size_t( 1 ) )
    	{
    	}
    
    Query::~Query()
    {
    	decr_use();
    }
    
    Query& Query::operator=( const Query& rhs )
    {
    	if( this != &rhs )
    	{
    		decr_use();
    		q = rhs.q;
    		use = rhs.use;
    		++*use;
    		return *this;
    	}
    	else
    		return *this;
    }
    
    set< Query_base::line_no > Query::eval( const TextQuery& t) const
    {
    	return q->eval( t );
    }
    
    ostream& Query::display( ostream& os ) const
    {
    	return q->display( os );
    }
    
    void Query::decr_use()
    {
    	if( --*use == 0 )
    	{
    		delete q;
    		delete use;
    	}
    }
    

    TextQuery.h

    #ifndef TEXTQUERY_H
    #define TEXTQUERY_H
    
    #include <string>
    #include <map>
    #include <vector>
    #include <fstream>
    #include <set>
    
    class TextQuery
    {
        public:
            typedef std::vector< std::string >::size_type line_no;
    
            void read_file( std::ifstream& is )
            {
                store_file( is );
                build_map();
            }
    
            std::set< line_no > run_query( const std::string& ) const;
            std::string text_line( line_no ) const;
    		line_no size() const;
    
        private:
            void store_file( std::ifstream& );
            void build_map();
    
            std::vector< std::string > line_of_text;
            std::map< std::string, std::set< line_no > > word_map;
    };
    
    #endif // CLASSTEXTQUERY_H_INCLUDED
    

    TextQuery.cpp

    #include "TextQuery.h"
    #include <iostream>
    #include <sstream>
    #include <utility>
    #include <stdexcept>
    
    using namespace std;
    
    void TextQuery::store_file( ifstream& in )
    {
        string line;
        while( getline( in, line ) )
        {
            line_of_text.push_back( line );
        }
    }
    
    void TextQuery::build_map()
    {
        line_no line = line_of_text.size();
    
        for( line_no i = 0; i != line; ++i )
        {
            istringstream stream( line_of_text[i] );
            string word;
            while( stream >> word )
            {
                map< string, set< line_no > >::iterator it = word_map.find( word );
                if( it != word_map.end() )
                {
                    ( it->second ).insert( i );
                }
                else
                {
                    set< line_no > temp;
                    temp.insert( i );
                    word_map.insert( make_pair( word, temp ) );
                }
            }
        }
    }
    
    set< TextQuery::line_no > TextQuery::run_query( const string& word ) const
    {
        map< string, set< line_no > >::const_iterator it = word_map.find( word );
    
        if( it != word_map.end() )
            return it->second;
    
        else
        {
            set< line_no > temp;
            return temp;
        }
    }
    
    string TextQuery::text_line( TextQuery::line_no line ) const
    {
        if( line < line_of_text.size() )
            return line_of_text[line];
        throw std::out_of_range( "Line Number is out of Range!" );
    }
    
    TextQuery::line_no TextQuery::size() const
    {
    	return line_of_text.size();
    }
    

    Ein paar Fehler( sind viel mehr ):

    1>e:\sources\übungsprogramme\von büchern und tutorials\uebungtextabfragehandle\uebungtextabfragehandle\query_base.h(28): error C2079: 'NotQuery::query' verwendet undefiniertes class 'Query'
    1>e:\sources\übungsprogramme\von büchern und tutorials\uebungtextabfragehandle\uebungtextabfragehandle\query_base.h(45): error C2079: 'BinaryQuery::lhs' verwendet undefiniertes class 'Query'
    1>e:\sources\übungsprogramme\von büchern und tutorials\uebungtextabfragehandle\uebungtextabfragehandle\query_base.h(45): error C2079: 'BinaryQuery::rhs' verwendet undefiniertes class 'Query'
    

    Danke schonmal

    Gruß freeG



  • Nicht gerade ein Minimalbeispiel ....

    class A;
    
    class B {
    public:
    B() : bb(0) {}
    
    private:
    int bb;
    A hallo;
    };
    

    sollte den selben Fehler produzieren ... nun rate warum .. und warum das hier nicht:

    class A;
    
    class B {
    public:
    B() : bb(0) {}
    
    private:
    int bb;
    A * hallo;
    };
    

    edit: Semikolons am Klassenende 😉



  • Und die Parameterübergabe geht nicht per Value, mach call-by-reference draus.
    Alternative zu den Pointern als Member sind natürlich Referenzen.



  • unskilled: 0, drakon: 1. :p *SCNR*

    Ok. Vielleicht nur 0.5 für mich, aber mein Artikel sollte bei vernünftigem lesen den Fehler klar machen.



  • Danke für die Tipps.
    Ich les ihn mir nochmal durch:D
    Ja sorry ich weiß war kein Minimalbeispiel 😃

    Gruß freeG

    EDIT:
    Mh aber da ich ja in beiden Klassen auch Objekte der anderen Header-Datei benötige, benötige ich ja die ganze Definition, aber das geht ja wiederum nicht...
    Verstehs grad echt net=(?

    Und nochmal die allgemeine Frage, ist es sinnvoller die Klassen so wie ich jetzt in eine Header-Datei zu packen und eine Source-Datei oder für jede Klasse ne eigene?

    Danke gruß freeG



  • Der Trick ist, dass du im Header nichts hast, was eine Definition verlangt. Wenn du so einen zyklische Abhängigkeit hast, dann musst du halt bei der einten Klasse einen Zeiger auf die andere Speichern (am besten nimmst du dafür einen Smart Pointer, damit du dennoch ein korrektes Verhalten hast beim zerstören).

    Bei Trennung kommt es drauf an. Die meisten halten es so, dass sie eine Klasse in in je einen Header und eine Soruce Datei aufteilen. Mache ich generell auch so, wenn auch mit Ausnahmen (für kleine Hilfsobjekte, oder bei verwandten Klassen).



  • ...



  • Ok sprich ich muss das Design so ändern, dass es Zeiger benutzt.

    Finds blos komisch da das ganze aus nem Buch ist.

    Gut wenn ich alles in eine Header packe müsst es ja gehen...war warscheinlich im Buch so gedacht.

    Gruß freeG



  • fr33g schrieb:

    Gut wenn ich alles in eine Header packe müsst es ja gehen...war warscheinlich im Buch so gedacht.

    Ohne Zeiger geht das auch nicht, da VOR dem Verwenden der Typ komplett bekannt sein muss - und wie willst du bei zwei Klassen beide vor der jeweils anderen definieren? 😃



  • drakon schrieb:

    [unskilled 0, drakon 1]

    joa 😞 .

    drakon schrieb:

    Der Trick ist, dass du im Header nichts hast, was eine Definition verlangt. Wenn du so einen zyklische Abhängigkeit hast, dann musst du halt bei der einten Klasse einen Zeiger auf die andere Speichern (am besten nimmst du dafür einen Smart Pointer, damit du dennoch ein korrektes Verhalten hast beim zerstören).

    Hm?
    Muss (für das Zerstören) nicht die Definition doch bekannt sein?
    imho sollte das hier nicht gehen:

    class b;
    
    class a
    {
     boost::scoped_ptr<b> b_;
    };
    
    class b
    {
      int x;
    };
    

    oder verwechsel ich da gerade was?

    bb



  • Wenn du statt scoped_ptr einen shared_ptr nimmst, dann geht auch das.



  • So, habs jetzt hinbekommen, dank Eurer Hilfe.
    Hab erst mal das mit Deklaration und Definition beachtet und dann Zeiger in den Klassen verwendet.

    Also vielen Dank nochmal.

    Gruß freeG



  • unskilled schrieb:

    drakon schrieb:

    Der Trick ist, dass du im Header nichts hast, was eine Definition verlangt. Wenn du so einen zyklische Abhängigkeit hast, dann musst du halt bei der einten Klasse einen Zeiger auf die andere Speichern (am besten nimmst du dafür einen Smart Pointer, damit du dennoch ein korrektes Verhalten hast beim zerstören).

    Hm?
    Muss (für das Zerstören) nicht die Definition doch bekannt sein?

    Ich bin mir nicht sicher, ob ich dich richtig verstehe, aber die Zerstörung findet ja im Destruktor statt und der liegt dann einfach nicht im Header, sondern in der .cpp und dort kannst/musst du natürlich die Definition einbinden.



  • drakon schrieb:

    Ich bin mir nicht sicher, ob ich dich richtig verstehe, aber die Zerstörung findet ja im Destruktor statt und der liegt dann einfach nicht im Header, sondern in der .cpp und dort kannst/musst du natürlich die Definition einbinden.

    Nein, vermutlich nicht.
    Ich dachte, mir eingebildet zu haben, dass bei der ersten Instanzierung eines smart-ptrs schon der Destruktor definiert sein muss, damit es richtig zerstört werden kann(da sonst nicht der richtige DTor aufgerufen wird, deshalb auch das checked-delete im SmartPtr-DTor).
    Allerdings hat Braunstein das wohl schon beantwortet - auch, wenn ich den Grund davon nicht verstehe...

    bb


Anmelden zum Antworten