Referenzparameter: "parse error before '&' token"



  • Die Fehlermeldung von KDevolop liest sich folgendermaßen:
    transaction.h:16:error:parse error before '&' token

    #ifndef TRANSACTION_H
    #define TRANSACTION_H
    
    #include <string>
    #include "account.h"
    using namespace std;
    
    enum TRANSACTIONTYPE{INCOMING, OUTGOING};
    
    //#########################################################
    
    class Transaction
    {
    public:
    	// ctors & dtors
        Transaction(string newName, float newAmount, TRANSACTIONTYPE newType, const Account& newOperationAccount); // <- Zeile 16
    	~Transaction();
    	// other methods
    	TRANSACTIONTYPE getType();
    private:
    	string name;
    	const Account& operationAccount;
    	TRANSACTIONTYPE type;
    	float amount;
    };
    
    #endif
    

    Ich verstehe die Fehlermeldung aber nicht, da account.h inkludiert wird und somit die Klasse Account bekannt sein müsste.



  • Bindet account.h vielleicht wiederum transaction.h ein?

    Jedenfalls ist das Einbinden von account.h unnötig. Eine einfache Vorausdeklaration der Klasse Account reicht aus:

    class Account;
    class Transaction {
       ... const Account& foobar ...
    };
    


  • Ja, account.h bindet wiederum transaction.h ein. Aber wieso spielt das eine Rolle, wenn beid Header-Dateien mit Include-Guards geschütz sind?

    Auf jeden Fall erstmal danke, denn die oben genannte Fehlermeldung ist schon mal aus der langen Liste der Fehlermeldungen verschwunden 😉



  • medici schrieb:

    Ja, account.h bindet wiederum transaction.h ein. Aber wieso spielt das eine Rolle, wenn beid Header-Dateien mit Include-Guards geschütz sind?

    Eben, genau die Include-Guards sind das Problem. Geh das mal von Hand durch ... zuerst wird Account eingebunden und ACCOUNT_H definiert. Dort drin wird als erstes Transaction eingebunden und TRANSACTION_H definiert. Wiederum als erstes wird Account eingebunden, diesmal aber übersprungen, weil ACCOUNT_H bereits definiert wurde. Wenn der Compiler zur Definition der Transaction-Klasse kommt, ist Account noch nicht bekannt.

    Folgerung: Niemals Header rekursiv einbinden. Niemals Überkreuz-Abhängigkeiten wie hier einführen. Mindestens einer der beiden Header muss mit Vorausdeklarationen vorliebnehmen.



  • Danke, macht Sinn!

    Ich habe jetzt allerdings immer noch einen Haufen Fehlermeldungen, die aber komischerweise nur in Dateien der Standardbibliothek ihren Ursprung haben sollen:

    */usr/include/c++/3.3/bits/stl_algobase.h:241: instantiated from `_OutputIter std::__copy(_RandomAccessIter, _RandomAccessIter, _OutputIter, std::random_access_iterator_tag) [with _RandomAccessIter = const Transaction*, _OutputIter = Transaction*]' 
    */usr/include/c++/3.3/bits/stl_algobase.h:260: instantiated from `_OutputIter std::__copy_aux2(_InputIter, _InputIter, _OutputIter, __false_type) [with _InputIter = const Transaction*, _OutputIter = Transaction*]' 
    */usr/include/c++/3.3/bits/stl_algobase.h:289: instantiated from `_OutputIter std::__copy_ni2(_InputIter, _InputIter, _OutputIter, __true_type) [with _InputIter = const Transaction*, _OutputIter = __gnu_cxx::__normal_iterator<Transaction*, std::vector<Transaction, std::allocator<Transaction> > >]' 
    */usr/include/c++/3.3/bits/stl_algobase.h:314: instantiated from `_OutputIter std::__copy_ni1(_InputIter, _InputIter, _OutputIter, __true_type) [with _InputIter = __gnu_cxx::__normal_iterator<const Transaction*, std::vector<Transaction, std::allocator<Transaction> > >, _OutputIter = __gnu_cxx::__normal_iterator<Transaction*, std::vector<Transaction, std::allocator<Transaction> > >]' 
    */usr/include/c++/3.3/bits/stl_algobase.h:349: instantiated from `_OutputIter std::copy(_InputIter, _InputIter, _OutputIter) [with _InputIter = __gnu_cxx::__normal_iterator<const Transaction*, std::vector<Transaction, std::allocator<Transaction> > >, _OutputIter = __gnu_cxx::__normal_iterator<Transaction*, std::vector<Transaction, std::allocator<Transaction> > >]' 
    */usr/include/c++/3.3/bits/vector.tcc:142: instantiated from `std::vector<_Tp, _Alloc>& std::vector<_Tp, _Alloc>::operator=(const std::vector<_Tp, _Alloc>&) [with _Tp = Transaction, _Alloc = std::allocator<Transaction>]' 
    */usr/include/c++/3.3/bits/stl_algobase.h:241: instantiated from `_OutputIter std::__copy(_RandomAccessIter, _RandomAccessIter, _OutputIter, std::random_access_iterator_tag) [with _RandomAccessIter = Account*, _OutputIter = Account*]' 
    */usr/include/c++/3.3/bits/stl_algobase.h:260: instantiated from `_OutputIter std::__copy_aux2(_InputIter, _InputIter, _OutputIter, __false_type) [with _InputIter = Account*, _OutputIter = Account*]' 
    */usr/include/c++/3.3/bits/stl_algobase.h:289: instantiated from `_OutputIter std::__copy_ni2(_InputIter, _InputIter, _OutputIter, __true_type) [with _InputIter = Account*, _OutputIter = __gnu_cxx::__normal_iterator<Account*, std::vector<Account, std::allocator<Account> > >]' 
    */usr/include/c++/3.3/bits/stl_algobase.h:314: instantiated from `_OutputIter std::__copy_ni1(_InputIter, _InputIter, _OutputIter, __true_type) [with _InputIter = __gnu_cxx::__normal_iterator<Account*, std::vector<Account, std::allocator<Account> > >, _OutputIter = __gnu_cxx::__normal_iterator<Account*, std::vector<Account, std::allocator<Account> > >]' 
    */usr/include/c++/3.3/bits/stl_algobase.h:349: instantiated from `_OutputIter std::copy(_InputIter, _InputIter, _OutputIter) [with _InputIter = __gnu_cxx::__normal_iterator<Account*, std::vector<Account, std::allocator<Account> > >, _OutputIter = __gnu_cxx::__normal_iterator<Account*, std::vector<Account, std::allocator<Account> > >]' 
    */usr/include/c++/3.3/bits/vector.tcc:107: instantiated from `__gnu_cxx::__normal_iterator<_Tp*, std::vector<_Tp, _Alloc> > std::vector<_Tp, _Alloc>::erase(__gnu_cxx::__normal_iterator<_Tp*, std::vector<_Tp, _Alloc> >) [with _Tp = Account, _Alloc = std::allocator<Account>]' 
    */home/medici/Desktop/accounting/src/person.cpp:36: instantiated from here 
    */usr/include/c++/3.3/bits/stl_algobase.h:241: error: non-static reference member `const Account&Transaction::operationAccount', can't use default assignment operator
    
    /usr/include/c++/3.3/bits/vector.tcc:230: instantiated from `void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<_Tp*, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = Transaction, _Alloc = std::allocator<Transaction>]' 
    */usr/include/c++/3.3/bits/stl_vector.h:603: instantiated from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = Transaction, _Alloc = std::allocator<Transaction>]' 
    */home/medici/Desktop/accounting/src/account.cpp:29: instantiated from here 
    */usr/include/c++/3.3/bits/vector.tcc:230: error: non-static reference member ` const Account&Transaction::operationAccount', can't use default assignment operator
    


  • Die Fehlermeldungen scheinen ja alle hierrauf hinauszulaufen:

    error: non-static reference member `const Account&Transaction::operationAccount', can't use default assignment operator

    Das sagt eigentlich schon alles. Schreib einen eigenen Assignment-Operator, oder, wenn das nicht möglich ist, mache ihn privat und lass die Implementierung weg.



  • Ok, ich habe aufgrund deines Ratschlags nun folgenden Zuweisungsoperator geschrieben:

    const Account& Account::operator=(const Account& source)
    {
    	// self-assignment test
    	if(this==&source)
    		return *this;
    	// assign
    	this->name = source.name;
    	this->category = source.category;
    	this->balance = source.balance;
    	this->transactions = new vector<Transaction>;
    	for(unsigned i = 0; i < source.transactions.size(); i++)
    	{
    		this->transactions.at(i) = source.transactions.at(i);
    	}
    	// return
    	return *this;
    }
    

    Doch ich bekomme noch folgende Fehlermeldung:

    /home/medici/Desktop/accounting/src/account.cpp:29: error: no match for 'operator=' in 'this->Account::transactions = (operator new(12), ((true, (<anonymous>->std::vector<_Tp, _Alloc>::vector [with _Tp = Transaction, _Alloc = std::allocator<Transaction>]((&allocator<Transaction>())), (<anonymous> <unknown operator> false))), <anonymous>))' 
    */usr/include/c++/3.3/bits/vector.tcc:128: error: candidates are: std::vector<_Tp, _Alloc>& std::vector<_Tp, _Alloc>::operator=(const std::vector<_Tp, _Alloc>&) [with _Tp = Transaction, _Alloc = std::allocator<Transaction>]
    
    /home/medici/Desktop/accounting/src/account.cpp:32: error: non-static reference member `const Account&Transaction::operationAccount', can't use default assignment operator
    

    Was ist falsch? Die kryptische Fehlermeldung hilft mir beim besten Willen nicht viel weiter.



  • this->transactions = new vector<Transaction>;
    

    ist übrigens Zeile 29.



  • medici schrieb:

    Doch ich bekomme noch folgende Fehlermeldung:

    /home/medici/Desktop/accounting/src/account.cpp:29: error: no match for 'operator=' in 'this->Account::transactions = (operator new(12), ((true, (<anonymous>->std::vector<_Tp, _Alloc>::vector [with _Tp = Transaction, _Alloc = std::allocator<Transaction>]((&allocator<Transaction>())), (<anonymous> <unknown operator> false))), <anonymous>))' 
    */usr/include/c++/3.3/bits/vector.tcc:128: error: candidates are: std::vector<_Tp, _Alloc>& std::vector<_Tp, _Alloc>::operator=(const std::vector<_Tp, _Alloc>&) [with _Tp = Transaction, _Alloc = std::allocator<Transaction>]
    
    /home/medici/Desktop/accounting/src/account.cpp:32: error: non-static reference member `const Account&Transaction::operationAccount', can't use default assignment operator
    

    Was ist falsch? Die kryptische Fehlermeldung hilft mir beim besten Willen nicht viel weiter.

    Du mußt einen assignment operator für Transaction schreiben, da der default operator nicht genutzt werden kann, da operationAccount eine Referenz auf einen const Account ist.



  • Ich habe den Zuweisungsoperator für die Klasse Account wieder entfernt und dafür einen für die Klasse Transaction geschrieben:

    //#########################################################
    
    const Transaction& Transaction::operator=(const Transaction& source)
    {
    	// self-assignment test
    	if(this == &source)
    		return *this;
    	// assign
    	this->name = source.name;
    	this->amount = source.amount;
    	this->type = source.type;
    	this->operationAccount = new Account(	source.getOperationAccount().getName(), 							    											source.getOperationAccount().getCategory(),
    											source.getOperationAccount().getBalance()	);
    }
    

    doch ich bekomme immer noch eine Fehlermeldung:

    /home/medici/Desktop/accounting/src/transaction.cpp:32: error: no match for 'operator=' in 'this->Transaction::operationAccount = (operator new(24), ((true, (<anonymous>->Account::Account(basic_string<char,std::char_traits<char>,std::allocator<char> >((+(+(+source)->Transaction::getOperationAccount())->Account::getName())), (+(+source)->Transaction::getOperationAccount())->Account::getCategory(), (+(+source)->Transaction::getOperationAccount())->Account::getBalance()), (<anonymous> <unknown operator> false))), <anonymous>))' 
    */home/medici/Desktop/accounting/src/account.h:19: error: candidates are: Account& Account::operator=(const Account&)
    

    Also wo liegt das Problem?



  • medici schrieb:

    Ich habe den Zuweisungsoperator für die Klasse Account wieder entfernt und dafür einen für die Klasse Transaction geschrieben:

    //#########################################################
    
    const Transaction& Transaction::operator=(const Transaction& source)
    {
    ...
    	this->operationAccount = new Account(	source.getOperationAccount().getName(), 							    											source.getOperationAccount().getCategory(),
    											source.getOperationAccount().getBalance()	);
    }
    

    operationAccount ist eine Referenz auf einen const Account. Da kannst du keinen Pointer zuweisen. Nimm die Zeile weg, dann sollte es klappen. Du müsstest dir aber überlegen, welche Logik genau hinter einem operationAccount steckt und ob eine Referenz auf einen const Account das richtige ist.



  • Danke, ich habe die Zeile entfernt und nun funktioniert es.
    Ich verstehe aber nicht wieso *g*

    Die nun geschrumpfte Definition des Zuweisungsoperators sieht so aus:

    const Transaction& Transaction::operator=(const Transaction& source)
    {
    	// self-assignment test
    	if(this == &source)
    		return *this;
    	// assign
    	this->name = source.name;
    	this->amount = source.amount;
    	return *this;
    }
    

    Der Sinn eines eigens definierten Zuweisungsoperators besteht doch gerade darin, dass man die flache Kopie, die der automatisch generierte Zuweisungsoperator ausführt gegen eine tiefe Kopie ersetzen will, oder?
    Aber der oben aufgeführte Zuweisungsopertor führt keine tiefen Kopien durch, sondern tut in meinen Augen nur das, was ein autom. gen. ZO auch tun würde.

    Kommentiere ich den selbst def. ZO aber aus, so habe ich wieder unzählige Fehlermeldungen... Wo ist mein Denkfehler?


Anmelden zum Antworten