5

When debugging my program I keep getting these two errors:

main.obj : error LNK2005: "class std::basic_istream > & __cdecl operator>>(class std::basic_istream > &,class Complex &)" (??5@YAAAV?$basic_istream@DU?$char_traits@D@std@@@std@@AAV01@AAVComplex@@@Z) already defined in Imaginary.obj

1>main.obj : error LNK2005: "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class Complex const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABVComplex@@@Z) already defined in Imaginary.obj

I have tried restarting my project to make sure that I created a console application and not something else on accident but that didn't work. Any direction would be greatly appreciated.

Here's my code:

imaginary.h

#ifndef imaginary_h_
#define imaginary_h_

#include <iostream>

class Complex
{    
    friend std::ostream & operator << (std::ostream& os, const Complex&);
    friend std::istream & operator >> (std::istream& is, Complex&);

private:    
    double real;
    double imag;
    char op;

public:    
    double r = real;
    double i = imag;
    char o = op;

    Complex()
    {    
    }

    Complex(double r, double i, char o)
    {    
    }

    bool userTest();    
};

#endif

std::ostream & operator << (std::ostream & os, const Complex & complex)    
{
    os << complex.r << complex.o << complex.i << "i" << "/n" << "/n";
    return os;
}

std::istream & operator >> (std::istream & is, Complex & complex)    
{
    is >> complex.r >> complex.o >> complex.i;
    return is;
}

Imaginary.cpp

#include "imaginary.h"    
#include <iostream>

bool Complex::userTest()

{
    if (op == '+' || op == '-')

    {
        return true;
    }

    else

    {
        std::cout << "Incorrect operand entry, please enter complex number as x+yi" << "/n" << "/n";

                return false;
    }

}

main.cpp

#include "imaginary.h"

#include <iostream>


int main()
{
    double userInput;

    std::cout << "Here you will add or subtract complex numbers." << "/n" << "/n";

    do

    {

        std::cout << "Please enter the real part of you complex number: " << "/n" << "/n";

                Complex complex;

        std::cin >> complex;

        std::cout << "/n" << "/n" << "/n/t" << "Note: Remember to enter your complex number in the format of x+yi to avoid an error";

                if (complex.userTest())
                {
                    std::cout << complex << "/n" << "/n";
                }

        std::cout << "Would you like to perform another complex number operation? " << "/n" << "/n/t";

                        std::cout << "Choose 1 for Yes and 2 for No" << "/n" << "/n";

        std::cin >> userInput;

    } while (userInput == 1);

    system("pause");

    return 0;
}
Brian Roper
  • 528
  • 7
  • 13
  • 1
    What are your file boundaries? Are the `operator<<` and `operator>>` definitions in the *header*? – Barry Aug 26 '15 at 17:04
  • Please divide the code into files and fix your string literals (which span multiple lines). – LogicStuff Aug 26 '15 at 17:06
  • The variables `i` and `r` will be initialized with the uninitialized values of `imag` and `real` only once. If you want to have `i` and `r` to reflect the changing values of `imag` and `real`, you will have to update `i` and `r` whenever `imag` and `real` are updated. So, why bother with the copies? You could, if you must, declare `i` and `r` as *references* to `imag` and `r`. But then ask yourself why you need copies? Are you trying to do something like *getter* and *setter* functions? Same principle applies to `o` and `op`. – Thomas Matthews Aug 26 '15 at 17:15
  • You seriously need to validate the `complex.o` variable before returning. For example, your code allows these inputs as valid entries: 4M6i, 4*6i, 4@6i, 4z6i. – Thomas Matthews Aug 26 '15 at 17:28

3 Answers3

13

You have two options:

  1. Move implementation of operator methods to a single cpp file
  2. Or declare the implementations as inline.

For example, in your header file, imaginary.hpp:

inline // <-- Add this line 
std::ostream & operator << (std::ostream & os, const Complex & complex)    
{
    os << complex.r << complex.o << complex.i << "i" << "/n" << "/n";
    return os;
}

inline  // <-- Add this line 
std::istream & operator >> (std::istream & is, Complex & complex)    
{
    is >> complex.r >> complex.o >> complex.i;
    return is;
}

#endif  // imaginary_h_  <-- This line was moved.

Or you can simply move the implementations into your imaginary.cpp file.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
8

The problem is that you have defined

std::ostream & operator<<(std::ostream &os, const Complex &complex) {
    os << complex.r << complex.o << complex.i << "i" << "/n" << "/n";
    return os;
}

std::istream & operator>>(std::istream &is, Complex &complex) {
    is >> complex.r >> complex.o >> complex.i;
    return is;
}

in your header file and because this is included in imaginary.cpp and main.cpp they are defined multiple times. This violates the single definition rule of C++.

You need to move the implementation of operator << and operator >> to the .cpp file and only leave the declaration in the header file. This would mean having

std::ostream & operator<<(std::ostream &os, const Complex &complex);

std::istream & operator>>(std::istream &is, Complex &complex);

in the header file after the definition of the class

class Complex {
    ...
};

and before the ending #endif. Then in imaginary.cpp you would have the definition

std::ostream & operator<<(std::ostream &os, const Complex &complex) {
    os << complex.r << complex.o << complex.i << "i" << "/n" << "/n";
    return os;
}

std::istream & operator>>(std::istream &is, Complex &complex) {
    is >> complex.r >> complex.o >> complex.i;
    return is;
}
IKavanagh
  • 6,089
  • 11
  • 42
  • 47
-1

Your error lies in your header guard:

    bool userTest();    
};

#endif // Here!

std::ostream & operator << (std::ostream & os, const Complex & complex)    
{
    os << complex.r << complex.o << complex.i << "i" << "/n" << "/n";
    return os;
}

When you include the header in your two file, they each compile the function in their respective compilation unit. That's why there's an error at link time.

Your file should look like this:

#ifndef imaginary_h_
#define imaginary_h_

#include <iostream>

class Complex
{    
    friend std::ostream & operator << (std::ostream& os, const Complex&);
    friend std::istream & operator >> (std::istream& is, Complex&);

private:    
    double real;
    double imag;
    char op;

public:    
    double r = real;
    double i = imag;
    char o = op;

    Complex()
    {    
    }

    Complex(double r, double i, char o)
    {    
    }

    bool userTest();    
};

std::ostream & operator << (std::ostream & os, const Complex & complex)    
{
    os << complex.r << complex.o << complex.i << "i" << "/n" << "/n";
    return os;
}

std::istream & operator >> (std::istream & is, Complex & complex)    
{
    is >> complex.r >> complex.o >> complex.i;
    return is;
}

#endif

But two other things:

  1. You should not put function definition in you header. You should put it in your cpp file
  2. You should seek to add #pragma once in addition of your header guard. It should prevent some error while keeping a standard code.
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141