weird compilation errors

Greetings. I am working through some exercises from C++ Primer, and I have run into a weird compile problem that makes no sense to me. Here is my code

main.cpp

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
#include <iostream>
#include "Sales_data.h"

using namespace std;

int main()
{
    Sales_data total;

    if( read( cin, total) )
    {
        Sales_data trans;
        while( read( cin, trans ) )
        {
            if( total.isbn() == trans.isbn() )
            {
                total.combine( trans );
            }
            else
            {
                print( cout, total ) << endl;
                total = trans;
            }
        }
        print( cout, total ) << endl;
    }
    else
    {
        cout << "No data" << endl;
    }

    return 0;
}


Sales_data.h
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
#ifndef SALES_DATA_H_INCLUDED
#define SALES_DATA_H_INCLUDED

#include <iostream>
using namespace std;

struct Sales_data
{
    std::string book_no;
    unsigned units = 0;
    double revenue = 0.0;

    Sales_data &combine( const Sales_data & );
    double avg_price() const { return revenue / units; }
    std::string isbn() const { return book_no; }

};

Sales_data& Sales_data::combine( const Sales_data &data)
{
    units += data.units;
    revenue += data.revenue;
    return *this;
}


istream &read(istream &is, Sales_data &item)
{
    double price = 0;
    is >> item.book_no >> item.units >> price;
    item.revenue = price * item.units;
    return is;
}

ostream &print(ostream &os, const Sales_data &item)
{
    os << item.isbn() << " " << item.units << " "
        << item.revenue << " " << item.avg_price();
    return os;
}


#endif // SALES_DATA_H_INCLUDED 


This works fine, but note the inclusion of the read and print functions in the header file. I really want these defined in a separate source file, with only function declarations in the header file. So I modify the header file to contain only the function declarations and create a separate .cpp file for the definition of read and print. These files are shown below.

revised Sales_data.h

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
#ifndef SALES_DATA_H_INCLUDED
#define SALES_DATA_H_INCLUDED

#include <iostream>
using namespace std;

struct Sales_data
{
    std::string book_no;
    unsigned units = 0;
    double revenue = 0.0;

    Sales_data &combine( const Sales_data & );
    double avg_price() const { return revenue / units; }
    std::string isbn() const { return book_no; }

};

Sales_data& Sales_data::combine( const Sales_data &data)
{
    units += data.units;
    revenue += data.revenue;
    return *this;
}

istream &read(istream &is, Sales_data &item);
ostream &print(ostream &os, const Sales_data &item);

#endif // SALES_DATA_H_INCLUDED 


Sales_data.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include "Sales_data.h"

using namespace std;

istream &read(istream &is, Sales_data &data)
{
    double price = 0;
    is >> data.book_no >> data.units >> price;
    data.revenue = data.units * price;
    return is;
}

ostream &print( ostream &os, const Sales_data &data )
{
    os << data.isbn() << " " << data.units << " "
        << data.revenue << " " << data.avg_price();
    return os;
}


However when I set it up like this, I get the following compile error

multiple definition of `Sales_data::combine(Sales_data const&)' at line 20 in the header file

This makes no sense to me because I have only defined the combine function once.
Last edited on
When you include a header file you're telling the toolchain, in a very real sense, to paste the contents of the header file in at that point of the source code file. By making another source code file, and including it in both 'main.cpp' and 'Sales_data.cpp' you are creating definitions for 'Sales_data::combine()' in two locations. The solution is to move the definition for that function into 'Sales_data.cpp' with the other two functions.
These instructions are for the compiler , to tell it to skip if its knows the class already . Which also means that the compiler looks multiple time at this header
1
2
3
4
#ifndef SALES_DATA_H_INCLUDED
#define SALES_DATA_H_INCLUDED

#endif 


remove this and put it in the cpp file

1
2
3
4
5
6
Sales_data& Sales_data::combine( const Sales_data &data)
{
    units += data.units;
    revenue += data.revenue;
    return *this;
}
Thanks that did the trick. btw I should have googled this first there's a few people who have had the same problem with the same exercise.
Topic archived. No new replies allowed.