moving functions from header to imp file..overloaded op

Feb 2, 2010 at 11:02pm
Hi I am trying to take a large code that has all its functions written in the header file, and im trying to move them to the implementation file. Theres an overloaded operation though that does not want to move, if I move it the program doesn't compile right. Ill post my updated code just for reference but im sure most won't want to bother looking at it all. Anyways..the code works fine..when I move all the functions the overloaded operator, wants a value to return...but it doesnt want one until I move it into the implementation file. If I add return input; to the bottom of it I get a bunch of errors like:

POS.obj : error LNK2005: "public: void __thiscall CInventory::init(void)" (?init@CInventory@@QAEXXZ) already defined in Inventory.obj


I guess ill post the code and maybe someone can try to compile it and see whats wrong? Thanks!

header:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// Inventory.h: interface for the CInventory class.
//
//////////////////////////////////////////////////////////////////////

#include <iostream>
#include <iomanip>
#include <string>
#include <istream>
#include <fstream>
#include <vector>
#include <ctime>

using namespace std;
class CInventory  
  {
  private:
    static double iCustomerCounter;  // counts receipts (valid or invalid) issued
    static const char *szError[]; // check enum error_msg
    static const double dblTaxes; // i.e 7.5%

    long lInventory;
    string strDescription;
    double dblPrice;
    char cTax;
  public:
	void init();
	void operator=(const CInventory &inv);
	bool operator==(const CInventory &item);
	friend bool is_inventory(vector<CInventory>& inv, const int&iNo);
	friend bool is_duplicate(vector<CInventory>& inv, const CInventory& invCheck);
	bool is_taxable();
	friend istream& operator>>(istream& input, const CInventory &item);
	friend istream& operator>>(istream& input, CInventory &item);
	static string get_heading();
	static void customerCounter();
	static string get_footer(double dblSum, double dblTaxes);
	friend ostream& operator<<(ostream& o, CInventory &item);
	static string get_printdate();
	static string get_item(CInventory &item, const int& iQuantity, double& dblPTax, double &dblSum);
	static string get_error(int idx, long lInventory);
	static string find_item(vector<CInventory>& inv, const long& lInventoryNo, const int& iQuantity, double& dblPTax, double& dblPSum);
    enum error_msg {NOT_FOUND, IS_DUPLICATE, E_QUANTITY};
    // methods
    const long& get_inventory() const {return lInventory;}
    const string& get_description() const {return strDescription;}
    const double& get_price() const {return dblPrice;};
    const char& get_tax() const {return cTax;}
    // construction / destruction
    // default constructor
    CInventory::CInventory() : lInventory(10000), strDescription(""), dblPrice(0.0), cTax('N'){}
    // copy constructor
    CInventory(const CInventory &inv) {*this = inv;}
    virtual CInventory::~CInventory(){lInventory = 0; dblPrice = 0.0; cTax = 'N'; strDescription = "";}
};
	


Main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// POS.cpp : Defines the entry point for the console application.
//

#include "inventory.cpp"


int main(int argc, char* argv[])
  {
  CInventory::customerCounter();
  filebuf fbInventory;
  fbInventory.open ("invent.dat",ios::in);
  filebuf fbReceipt;
  fbReceipt.open("receipt.dat", ios::out);
  istream inv(&fbInventory);
  ostream rec(&fbReceipt);
  vector<CInventory> v;
  CInventory item;

  // Get the inventory from the inventory file
  while(!inv.eof()) {
    inv >> item;
    if (item.get_description() != "") {
      v.push_back(item);
      }
    }

  // some debug output !
  for (int i = 0; i < v.size(); i++) {
    cout << v[i] << endl;
    }
  rec << CInventory::get_heading();
  cout << CInventory::get_heading();

  char input;
  long lInventoryNo = 0;
  int iQuantity = 0;
  double dblTax = 0.0;
  double dblSum = 0.0;
  string strOutput = "";
  do {
    input = 0;
    lInventoryNo = 0;
    iQuantity = 0;
    
    cout << "Enter Inventory No plus Quantity separated by space > ";
    cin >> lInventoryNo >> iQuantity;
    if (iQuantity != 0) {
      input = 'y';
      strOutput = item.find_item(v, lInventoryNo, iQuantity, dblTax, dblSum);
      cout << strOutput << endl;
      rec << strOutput << endl;
      }
    else {
      rec << CInventory::get_footer(dblSum, dblTax);
      cout << CInventory::get_footer(dblSum, dblTax);
      cout << endl << "Help another customer > ";
      cin >> input;
      if (tolower(input == 'y')) {
		CInventory::customerCounter();
        rec << CInventory::get_heading();
        cout << CInventory::get_heading();
        dblSum = 0.0;
        dblTax = 0.0;
        }
      }
    cin.ignore();
    }while(tolower(input) == 'y');
  system("pause");
	return 0;
  }

Last edited on Feb 2, 2010 at 11:03pm
Feb 2, 2010 at 11:03pm
heres the imp file

Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
// Inventory.cpp: implementation of the CInventory class.
//
//////////////////////////////////////////////////////////////////////

#include "Inventory.h"

void CInventory::init()
	{
	lInventory = 0;
	dblPrice = 0.0;
	cTax = 0;
	strDescription = "";
	}


    // copies information from inv to *this
    void CInventory::operator=(const CInventory &inv)
      {
      lInventory = inv.get_inventory();
      strDescription = inv.get_description();
      dblPrice = inv.get_price();
      cTax = inv.get_tax();
      }
  
    // compares *this with item
    bool CInventory::operator==(const CInventory &item)
      {
      return item.get_tax() == cTax && 
             item.get_price() == dblPrice && 
             item.get_description() == strDescription && 
             item.get_inventory() == lInventory;
      }

    // checks whether item numbers is present along a vector
    bool is_inventory(vector<CInventory>& inv, const int&iNo)
      {
      for (int i = 0; i < inv.size(); i++) {
        if (inv[i].lInventory == iNo) 
          return true;
        }
      return false;
      }

    // checks for duplicated items along a vector
    bool is_duplicate(vector<CInventory>& inv, const CInventory& invCheck)
      {
      for (int i = 0; i < inv.size(); i++) {
        if (inv[i] == invCheck) 
          return true;
        }
      return false;
      }

    // checks whether tax flag is T
	bool CInventory::is_taxable()
      {
      return cTax == 'T';
      }

    // fills one CInventory item from i.e. invent.dat
    istream& operator>>(istream& input, const CInventory &item)          
        {          
             operator>>(input, (CInventory &)item);    
			 return input;
        }

    istream& operator>>(istream& input, CInventory &item)
{
long lInventory = 0;
string strDescription = "";
double dblPrice = 0.0;
char cTax = 0;
// default item to empty
item.init();
if (!input.eof()) {
input >> lInventory >> strDescription >> dblPrice >> cTax;
// A complete inventory item has all these information: in case not, the input will fail
// and the variables will keep their values!!!!!!
if (lInventory != 0 && strDescription != "" && dblPrice != 0.0 && cTax != 0) {
item.lInventory = lInventory;
item.strDescription = strDescription;
item.dblPrice = dblPrice;
item.cTax = cTax;
}
}
return input;
}

    string CInventory::get_heading()
      {
      string strReturn = CInventory::get_printdate();
      strReturn += "\n";
      strReturn += "Customer ";
      CInventory::iCustomerCounter;
      strReturn += CInventory::iCustomerCounter + '0';
      strReturn += "\n===================================================\n\n";
      return strReturn;
      }
	void CInventory::customerCounter()
	{
		++CInventory::iCustomerCounter;
	}
    string CInventory::get_footer(double dblSum, double dblTaxes)
      {
      char szFooter[512];
      sprintf(szFooter, "\n%s\nSub Total: %10.2lf\nTaxes    : %10.2lf\n%s\nTotal    : %10.2lf\n%s\n",        
                      "---------------------------------------------------",
                      dblSum, 
                      dblTaxes, 
                      "---------------------------------------------------",
                      dblSum + dblTaxes,
                      "===================================================");
      string strRet = szFooter;
      return strRet;
      }
    ostream& operator<<(ostream& o, CInventory &item)
      {
      o << setw(5)  << item.get_inventory() << " " << setw(12) << item.get_description() << setw(8) << fixed << setprecision(2) << item.get_price() << " " << item.get_tax();
      return o;
      }
    // calculates print date and time
    string CInventory::get_printdate()
      {
      struct tm *today;
      char tmpbuf[128];
      string strDate;
      time_t ltime;
      time(&ltime);
      today = localtime( &ltime );
      strftime( tmpbuf, sizeof(tmpbuf), "%b %d, %Y  %I:%M", today );        
      strDate = tmpbuf;

      return strDate;      
      }

    // returns a line item on the customer receipt
    string CInventory::get_item(CInventory &item, const int& iQuantity, double& dblPTax, double &dblSum)
      {
      string strReturn;
      char szItemLine[256];
      memset(szItemLine, 0, sizeof(szItemLine));
      string strD = item.get_description();
      double dblP = item.get_price();
      string strTax = item.is_taxable() ? " TX" : " N";      

      sprintf(szItemLine, "%12.12s %3d @ %6.2lf %-2.2s %7.2lf", 
        strD.c_str(), 
        iQuantity,
        dblP,
        strTax.c_str(),
        iQuantity * dblP);
      dblSum+= iQuantity * item.get_price();
      if (item.is_taxable()) {
        dblPTax += dblTaxes * (iQuantity * item.get_price());
        }
      strReturn = szItemLine;
      return strReturn;
      }

    // returns one of three existing errors
    string CInventory::get_error(int idx, long lInventory)
      {
      string strReturn;
      char szErr[256];
      if (idx >= NOT_FOUND || idx <= E_QUANTITY){
        //sprintf(szErr, "*** item %ld %s ***", lInventory, idx == NOT_FOUND ? "not found!" : idx == IS_DUPLICATE ? "duplicate in Inventory!" : "wrong quantity!" );
        sprintf(szErr, szError[idx], lInventory);
        strReturn = szErr;

        }
      return strReturn;
      }

    // performs requested error handling and prints an error message line rather
    // than an item line, in case
    // a) item not found
    // b) item duplicated
    // c) quantity related error (i.e. less than one)
    string CInventory::find_item(vector<CInventory>& inv, const long& lInventoryNo, const int& iQuantity, double& dblPTax, double& dblPSum)
      {
      string strReturn;
      bool bFound = false, 
        bDuplicate = false, 
        bQuantity = iQuantity > 0;
      int iFound = 0;
      if (!bQuantity) {
        strReturn = get_error(E_QUANTITY, lInventoryNo);
        }
      for (int i = 0; i < inv.size(); i++) {
        if (inv[i].get_inventory() == lInventoryNo) {
          if (bFound) {
            if (strReturn.length() > 0) {
              strReturn += "\n";
              }
            strReturn += get_error(IS_DUPLICATE, lInventoryNo);
            bDuplicate = true;
            }
          else {
            bFound = true;
            iFound = i;
            }
          }
        }
      if (!bDuplicate && bQuantity && bFound) {
        strReturn = get_item(inv[iFound], iQuantity, dblPTax, dblPSum);
        }
      if (!bFound) {
        strReturn = get_error(NOT_FOUND, lInventoryNo);
        }
      return strReturn;
      }
  

const double CInventory::dblTaxes = 0.075;
// each time the program terminates this counter resets to 0
// clean solution could be to create a date dependency and
// write intermediate results to a i.e. file
double CInventory::iCustomerCounter = 0;
const char *CInventory::szError[] = 
  {
  "%ld is not in inventory",
  "%ld has duplicate inventory #",
  "%ld QUANTITY less than 1"
  };

Feb 2, 2010 at 11:58pm
Don't #include cpp files.

main.cpp should be including inventory.h, not inventory.cpp
Feb 3, 2010 at 12:33am
wow..im surprised I didnt try that..as thats how the file was setup before I moved the functions...I just thought the example problem I had was including them in a row...Can someone explain to me why it works like that..I thought maybe it had to go in a line and create 3 files connected together...The header is included in the main program...but when do the functions get loaded? Does the header automatically load all the files that are including it?

Thanks!
Feb 3, 2010 at 4:18am
Very basically, it's a two step process:

1) Compiling takes all the function bodies in ONE file (read: one source file, aka a .cpp file) and compiles them

2) Linking takes the compiled functions from several files and ties them together into one executable.


A function can only have 1 body in the program. If multiple bodies are found in different .cpp files, the Linker will error at you because it won't know which body to use*

*unless the functions are globally static or inline -- in which case the linker doesn't see them at all -- but whatever

#include is pretty much a fancy "copy/paste" operation. When you include a file, the compiler basically just copy pastes the file into the source code.

So something like this, while strange and ill advised, is perfectly legal:

1
2
/* a.h */
+ 3;

1
2
3
4
5
6
7
8
9
10
11
12
/* main.cpp */
#include <iostream>

int main()
{
    int foo = 5
#include "a.h"

    std::cout << foo;  // outputs 8 (foo == 5+3)

    return 0;
}



--------

Now what this means is.... when you #include a .cpp file in another .cpp file, you're copying all the function bodies from one .cpp into the other. So in your above code... the linker found function bodies for CInventory::init() in both inventory.cpp (where it is defined), and in POS.cpp (where it was #included) so it threw an error at you because it didn't know which one you wanted.

Hope that makes sense.
Topic archived. No new replies allowed.