1

I've searched (and found) topics to this error, but wasn't able to apply them to my specific situation, yet. So here it goes:

Rational.h

#include <iostream>
class Rational{
public:
    Rational(int a = 0, int b = 1);
    Rational(const Rational &number);
    ~Rational();

    static Rational add(const Rational &a, const Rational &b);
    static Rational sub(const Rational &a, const Rational &b);
    static Rational mult(const Rational &a, const Rational &b);
    static Rational div(const Rational &a, const Rational &b);

    void reduce(Rational a);

    int get_nom() const;
    int get_denom() const;
    void set_nom(int a);
    void set_denom(int b);

    void printOut();

private:
    int nom;
    int denom;

    int greatCommonDiv(int a, int b);
};

Rational.cpp

#include <iostream>

class Rational{
public:
    Rational(int a = 0, int b = 1):
        nom(a), denom(b){
    }
    Rational(const Rational &number):
        nom(number.get_nom()), denom(number.get_denom()){
    }
    ~Rational(){
    }

    static Rational add(const Rational &a, const Rational &b){
        Rational sum( ((a.get_nom() * b.get_denom()) + (a.get_denom() * b.get_denom())), (a.get_denom() * b.get_denom()) );
        sum.reduce();
        return sum;
    }
    static Rational sub(const Rational &a, const Rational &b){
        Rational diff( ((a.get_nom() * b.get_denom()) - (a.get_denom() * b.get_denom())), (a.get_denom() * b.get_denom()) );
        diff.reduce();
        return diff;
    }
    static Rational mult(const Rational &a, const Rational &b){
        Rational product(a.get_nom() * b.get_nom(), a.get_denom() * b.get_denom());
        product.reduce();
        return product;
    }
    static Rational div(const Rational &a, const Rational &b){
        Rational quotient(a.get_nom() * b.get_denom(), a.get_denom() * b.get_nom());
        quotient.reduce();
        return quotient;
    }
    void reduce(){
        int ggT = greatCommonDiv(nom, denom);
        nom = nom / ggT;
        denom = denom / ggT;
    }

    int get_nom() const { return nom; }
    int get_denom() const { return denom; }
    void set_nom(int a){ nom = a; }
    void set_denom(int b){ denom = b; }

    void printOut(){
        std::cout << nom << "/" << denom << std::endl;
        return;
    }

private:
    int nom;
    int denom;

    int greatCommonDiv(int a, int b){           
        if(b == 0)
            return a;
        else return greatCommonDiv(b, a % b);
    }
};

Source.cpp

#include <iostream>
#include <Rational.h>

int main(){
Rational a(5,3);
a.printOut();
}

MSVS gives me 3 errors:

1>Source.obj : error LNK2019: unresolved external symbol "public: __thiscall Rational::Rational(int,int)" (??0Rational@@QAE@HH@Z) referenced in function _main

1>Source.obj : error LNK2019: unresolved external symbol "public: __thiscall Rational::~Rational(void)" (??1Rational@@QAE@XZ) referenced in function _main

1>Source.obj : error LNK2019: unresolved external symbol "public: static void __cdecl Rational::printOut(void)" (?printOut@Rational@@SAXXZ) referenced in function _main

I can't figure out, why this happens as I'm pretty certain that he can find the .h and .cpp files at the right places.

Community
  • 1
  • 1
DenverCoder21
  • 879
  • 3
  • 16
  • 34
  • Did you compile Rational.cpp to get a Rational.obj? Did you link in Rational.obj when trying to create an executable? – user93353 Aug 06 '13 at 09:11
  • possible duplicate of [Why am I getting this error ? "unresolved external symbol"](http://stackoverflow.com/questions/15691263/why-am-i-getting-this-error-unresolved-external-symbol) – user93353 Aug 06 '13 at 09:13
  • I just hit F7 in Visual Studio and aiming to have it run in a console windows. I added '#include "Rational.h" to the .cpp file, the errors are gone but instead I'm getting 'Rational: 'class' type redefinition'. – DenverCoder21 Aug 06 '13 at 09:14

1 Answers1

3

So you solved your linker problem yourself. Regarding the "class type redefinition":

The compiler is right. You can/shall/must only define the class once, as you did correctly in the header file. The cpp file should look like this instead:

#include "Rational.h"

Rational Rational::add(const Rational &a, const Rational &b){
    Rational sum( ((a.get_nom() * b.get_denom()) + (a.get_denom() * b.get_denom())), (a.get_denom() * b.get_denom()) );
    sum.reduce();
    return sum;
}

...

You get the basic idea: Whatever is not defined (only declared) in the header, you define in the cpp. Always prefixed with Classname::. Things you defined in the header (like your constructor) you don't have to defined again.

firefrorefiddle
  • 3,795
  • 20
  • 31
  • Thank you very much. So I took out the whole initialisations of variables in the .cpp as well as the 'class-block'. But shouldn't I have the constructor prefixed with 'Rational::' aswell because I'm defining it in the .cpp in difference to the declaration in the .h file? – DenverCoder21 Aug 06 '13 at 09:25
  • If you define it in the cpp: Yes. But there is a complete definition in your header file, you can just leave it there and never mention it in the cpp. – firefrorefiddle Aug 06 '13 at 09:27
  • Sorry I don't see how the constructor and destructor are a complete definition in the .h file. How would I need to change the code in order to get it right? – DenverCoder21 Aug 06 '13 at 09:30
  • Further, the compiler now tells me that 'static should not be used on member functions defined at file scope' for the add/sub/mult/div functions. – DenverCoder21 Aug 06 '13 at 09:34
  • Oh sorry, I looked at the wrong place. You are right: You also need to define the constructor, qualified just like the methods. – firefrorefiddle Aug 06 '13 at 09:34
  • Yes. Remove `static`. I wasn't sure about this, as I didn't use c++ for a while. – firefrorefiddle Aug 06 '13 at 09:35
  • Here is an excellent answer to all your questions: http://stackoverflow.com/questions/116687/problem-linking-static-methods-in-c – firefrorefiddle Aug 06 '13 at 09:37
  • I removed the static statements, which now leaves me with 'Rational::Rational' : redefinition of default parameter : parameter 2' ''Rational::Rational' : redefinition of default parameter : parameter 1' /I'll check the link out. Thanks alot for your help! – DenverCoder21 Aug 06 '13 at 09:39
  • Ah yes. Give default parameter values only in the header. – firefrorefiddle Aug 06 '13 at 09:44