Duplicate Symbol for architecture x86_64

(from an old problem, I found a new issue that I did not expect)

I have the following error (see output) :

Output

1
2
3
4
5
6
7
8
9
  duplicate symbol 'Rectangle::yardsAvail' in:
    rect.o
    testRect.o
duplicate symbol 'Rectangle::yardsAvail' in:
    rect.o
    rectEnhanceStaticFriends.o
ld: 2 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
cppcompile:15: no such file or directory: ./rectEnhanceStaticFriends


Here is the code :

rectEnhanceStaticFriends
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
  #include <iostream> //
#include <iomanip>
#include <cstring>
#include <string>
#include "rect.h"
#include "testRect.h"
using namespace std;

int main()
{

    Rectangle::setYards(100);
    Rectangle r1(20, 20, "Kitchen");
    Rectangle r2(20, 20, "Bathroom");
    Rectangle r3(20, 20, "Office");
    TestRect tr;

    cout << "Test on r1: " << tr.tester(r1) << endl;
    cout << "Test on r2: " << tr.tester(r2) << endl;
    cout << "Test on r3: " << tr.tester(r3) << endl;

    Rectangle house[] = {Rectangle(10, 12, "Kitchen"),
                         Rectangle(20, 20, "Bedroom"),
                         Rectangle(8, 12, "Offce")};

    for (int i = 0; i < 3; i++)
    {

        if (strcmp(house[i].printName(), "Offce") == 0)
        {
            // cout << "oui\n";
            house[i].setName("Office");
        };

        cout << "Area for " << house[i].printName() << " is : " << house[i].getArea() << endl;
    }

    if (house[1].getArea() > house[2].getArea() && house[1].getArea() > house[3].getArea())
    {
        cout << house[1].printName() << " has the biggest area.\n";
    }
    else if (house[2].getArea() > house[1].getArea() && house[2].getArea() > house[3].getArea())
    {
        cout << house[2].printName() << " has the biggest area\n";
    }
    else
    {
        cout << house[3].printName() << " has the biggest area\n";
    }

    //there is an error house[3] go beyond the array..
    return 0;
}


testRect.h
1
2
3
4
5
6
7
8
9
10
11
12
  #ifndef TESTRECT_H
#define TESTRECT_H

class Rectangle; //forward declaration of class Rectangle

class TestRect
{
public:
    bool tester(Rectangle &);
};

#endif 


testRect.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  #include <iostream> //
#include <iomanip>
#include <string>
#include "rect.h"
#include "testRect.h"
using namespace std;

bool TestRect::tester(Rectangle &r)
{
    bool testResult = false;
    if (r.width > 0 && r.length > 0)
        testResult = true;
    return testResult;
}


rect.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
  // Rec header file
#ifndef RECT_H
#define RECT_H
#include "testRect.h"

class Rectangle
{
private:
    double width;
    double length;
    char *name;
    static double yardsAvail; //indicate how many yards of perimeter are available to make rectangle
    void initName(const char *n);
    void initName(const char *n, int size);

public:
    //constructors
    Rectangle();
    Rectangle(double, double,
              const char *);
    //destructor
    ~Rectangle() { delete[] name; };
    void setWidth(double);
    void setLength(double);
    void setWidth(char *);
    void setLength(char *);
    void setName(const char *);
    int getWidth() const;
    int getLength() const;
    double getArea() const;
    char *printName() const
    {
        return name;
    }
    //added parts
    static void setYards(double);
    friend class TestRect;
    friend bool TestRect::tester(Rectangle &);
};
double Rectangle::yardsAvail = 0; //added parts

#endif 



rect.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
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
#include <iostream> //
#include <iomanip>
#include <string>
#include "rect.h"

using namespace std;

Rectangle::Rectangle()
{
    width = 0;
    length = 0;
    initName("Default");
}

Rectangle::Rectangle(double x, double y, const char *z)
{
    width = x;
    length = y;
    initName(z);

    double yardsReqd = 2 * x + 2 * y;
    if (yardsAvail - yardsReqd < 0)
    {
        cout << "Not enough yard..\n";
        width = 0;
        length = 0;
    }

    yardsAvail -= yardsReqd;
}

void Rectangle::initName(const char *n)
{
    name = new char[258];
    strcpy(name, n);
};

void Rectangle::initName(const char *n, int size)
{
    name = new char[size];
    strcpy(name, n);
};

void Rectangle::setWidth(double w)
{
    width = w;
}

void Rectangle::setLength(double l)

{
    length = l;
}

void Rectangle::setName(const char *newname)
{
    //newname.newName = "Office";
    strcpy(name, newname);
}

double Rectangle::getArea() const
{
    return width * length;
}

//added part
void Rectangle::setYards(double y)
{
    yardsAvail = y;
}


I found this article interesting : https://chunminchang.github.io/blog/post/how-to-avoid-duplicate-symbols-when-compiling
I hope it can give some clue, or help on how to fix this issue that I got in the output. I'm using VSC.
You might want to check your CMakeLists.txt. If you have multiple CMakeLists.txt, it is most likely that you included "Rectangle::yardsAvail" multiple times
> double Rectangle::yardsAvail = 0; //added parts
Yeah, this needs to be in ONE .cpp file, not the header file.

Why is it static anyway, seems like bad code to me.


> char *name;
You already include string, so make this a std::string and save yourself some future pain.
rect.h

Don't put L40 in the header. Try putting it at the end of rect.cpp
I moved the L40 from rect.h to rect.cpp. Ty, it gives me an acceptable output right now. Can move forward.


salem c : I'm following the instruction of an exercise that's why I use static and char *name (still at beginner level)
Topic archived. No new replies allowed.