Search code examples
c++header

Why does my compiler say that my functions are defined multiple times?


I'm learning to create sets in C++. I wrote this program that has some bugs in it because it's not fully done but that's not my main concern right now. I used a .h file to declare some functions and I defined them in my .cpp file. My compiler has given me a few errors.

1>SetMain.obj : error LNK2005: "public: __cdecl Set::Set(class Set const &)" (??0Set@@QEAA@AEBV0@@Z) already defined in Set.obj

1>SetMain.obj : error LNK2005: "public: __cdecl Set::Set(void)" (??0Set@@QEAA@XZ) already defined in Set.obj

1>SetMain.obj : error LNK2005: "public: __cdecl Set::~Set(void)" (??1Set@@QEAA@XZ) already defined in Set.obj

1>SetMain.obj : error LNK2005: "public: bool __cdecl Set::insert(int)" (?insert@Set@@QEAA_NH@Z) already defined in Set.obj

1>SetMain.obj : error LNK2005: "public: bool __cdecl Set::isElement(int)" (?isElement@Set@@QEAA_NH@Z) already defined in Set.obj

1>SetMain.obj : error LNK2005: "public: void __cdecl Set::print(void)" (?print@Set@@QEAAXXZ) already defined in Set.obj

1>SetMain.obj : error LNK2005: "public: bool __cdecl Set::remove(int)" (?remove@Set@@QEAA_NH@Z) already defined in Set.obj

1>C:\Users\OmarA\source\repos\Set\x64\Debug\Set.exe : fatal error LNK1169: one or more multiply defined symbols found

I looked up the errors but I still don't understand what I did wrong.

My .h file

#pragma once

#include <stdio.h>

class Set
{
    int elementNum;
    int* pData;
public:
    // Initialize an empty set.
    Set();

    // Write a copy constructor. Do not forget the dynamically allocated attributes!
    Set(const Set& theOther);

    // Write a destructor: release dynamically allocated resources.
    ~Set();

    // Insert a new element into the set. If no memory can be allocated, false is to be returned.
    // If the set contains some element, then the same element cannot be inserted again;
    // in this case the method should return true indicating that the element is already there in the set.
    bool insert(int element);

    // Remove an element from the set.
    // If there is no such element in the set, then the method should return flase.
    bool remove(int element);

    // Check if the given element is contained by the set.
    bool isElement(int element);

    // Print the set elements separated by spaces. Puts a new line before the first an after the last elements.
    void print();
};

My .cpp file:

#include "Set.h"
#include <limits.h>
#include <iostream>

Set::Set()
{
    elementNum = 0;
    pData = new int[elementNum];
}

Set::Set(const Set& theOther)
{
    elementNum = theOther.elementNum;
    pData = new int[elementNum];
    for (int i = 0; i < elementNum; i++)
    {
        pData[i] = theOther.pData[i];
    }
} 

Set::~Set()
{
    elementNum = 0;
    delete[] pData;
}

bool Set::insert(int element)
{
    if (elementNum > INT_MAX)
    {
        return false;
    }
    
    if (isElement(element))
    {
        return false;
    }
    int* ptrTemp = new int[elementNum+1];
    for (int i = 0; i < elementNum; i++)
    {
        ptrTemp[i] = pData[i];
    }
    ptrTemp[elementNum] = element;
    elementNum++;
    delete[] pData;
    pData = new int[elementNum];
    for (int i = 0; i < elementNum; i++)
    {
        pData[i] = ptrTemp[i];
    }
    delete[] ptrTemp;
    return true;
}

bool Set::remove(int element)
{
    if (!isElement(element)) 
    {
        printf("No such element exists in the set\n");
        return false;
    }
    int* ptrTemp = new int[elementNum-1];

    for (int i = 0, j = 0; i < elementNum; i++, j++)
    {
        if (element == pData[i])
        {
            j--;
        }
        else
        {
            ptrTemp[j] = pData[i];
        }
    }
    elementNum--;
    pData = new int[elementNum];
    for (int i = 0; i < elementNum; i++)
    {
        pData[i] = ptrTemp[i];
    }
    delete[] ptrTemp;
    return true;
}

bool Set::isElement(int element)
{
    for (int i = 0; i < elementNum; i++)
    {
        if (element == pData[i])
        {
            return true;
        }
    }

    return false;
}

void Set::print()
{
    for (int i = 0; i < elementNum; i++)
    {
        std::cout << pData[i];
    }
}

My main file

#include "Set.cpp"

void printSet(Set s);
void printSet(Set* ps);


void printSet(Set s)
{
    s.print();
}


void printSet(Set* ps)
{
    ps->print();
}


int main(void)
{
    Set s1; // a Set object is created

    // Insert is tested
    s1.insert(1);
    s1.insert(1);  // Inserting a duplicated element, the total number of elements should not change at this line
    s1.insert(2);
    s1.print();

    // Testing isElement method
    if (s1.isElement(1) && s1.isElement(2) && !s1.isElement(3))
    {
        printf("isElement seems OK.\n");
    }

    // Put a breakpoint here and observe the copy constructor calls

    // Testing a copy constructor
    Set s2(s1); // Explicit copy constructor call
    Set s3 = s1;    // Copy constructor is called by initialization


    printSet(s1);   // The parameter is passed by value -> copy is created -> copy constructor is called
    printSet(s2);   // The parameter is passed by value -> copy is created -> copy constructor is called
    printSet(&s3);  // The address of set object is passed -> copy constructor is NOT called


    s2.remove(1);   // Testing remove method
    printSet(s2);   // Checking the result of remove operation
    printSet(s1);   // Making sure that the other set object remained unchanged (if not -> problems in copy constructor)

    s2.remove(1);   // Further testing of remove method: make sure that false is returned. Use debugger.
    return 0;
}

/* After having checked and executed the code, modify the following function
    void printSet(Set s);
   to have a reference type parameter:
    void printSet(Set &s);
   Remember to do it twice: in the implementation (.cpp) and in the prototype (header).
*/

Also don't mind the comments this is for school.


Solution

  • Include the header instead of the cpp file.

    #include "Set.h"

    #include exists for this very reason. #include exists because headers exist that can be included. Headers allow one to separate implementation and declaration.