C++ – Unresolved External Symbol, Header File Cause

clinkerunresolved-external

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.

Best Answer

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.

Related Topic