1

The error I get is

(base) ethanordaz@Ethans-MBP Fraction % g++ main.cpp fractionClass.cpp
Undefined symbols for architecture x86_64:
  "fraction::Fraction fraction::Fraction::operator*<fraction::Fraction>(fraction::Fraction)", referenced from:
      _main in main-8169dc.o
  "fraction::Fraction fraction::Fraction::operator+<int>(int)", referenced from:
      _main in main-8169dc.o
ld: symbol(s) not found for architecture x86_64

Main.cpp

#include <iostream>
#include <cmath>
#include <string>
#include "fractionClass.h"

int main()
{
    fraction::Fraction myFrac2(2,3);
    fraction::Fraction newFrac = myFrac2 + 1;
    myFrac2 = newFrac*myFrac2;
    std::cin >> myFrac2;
    std::cout << myFrac2 << std::endl;
    std::cout << newFrac << std::endl;
    return 0;
}

fractionClass.cpp

#include <iostream>
#include <cmath>
#include <string>
#include "fractionClass.h"

namespace fraction {

Fraction::Fraction(int x, int y) {
    numerator = x;
    denominator = y;
    simplify();
}
template <typename Number>
Fraction::Fraction(Number x) {
    int xint = (int)x;
    int zeros = 0;
    if (xint-x != 0){
        std::string tempString = std::to_string(x-xint);
        zeros = tempString.size();
    }
    numerator = x * std::pow(10,zeros);
    denominator = std::pow(10,zeros);
    simplify();
}
Fraction::Fraction(){

}
double Fraction::getDecimal() {
    double decimal = (double)numerator/(double)denominator;
    return decimal;
}
template <typename Number>
void Fraction::multiply(Number x) {
    int xint = (int)x;
    int zeros = 0;
    if (xint-x != 0){
        std::string tempString = std::to_string(x-xint);
        zeros = tempString.size();
    }
    numerator = numerator * x;
    denominator = denominator * std::pow(10,zeros);
    simplify();
}
void Fraction::multiply(Fraction x) {
    numerator = numerator * x.numerator;
    denominator = denominator * x.denominator;
    simplify();
}
template <typename Number>
void Fraction::divide(Number x) {
    int xint = (int)x;
    int zeros = 0;
    if (xint-x != 0){
        std::string tempString = std::to_string(x-xint);
        zeros = tempString.size();
    }
    numerator = numerator * std::pow(10,zeros);
    denominator = denominator * x;
    simplify();
}
void Fraction::divide(Fraction x) {
    numerator = numerator * x.denominator;
    denominator = denominator * x.numerator;
    simplify();
}
void Fraction::simplify() {
    int a = numerator;
    int b = denominator;
    int greatestCommonDivisor;
    int greatestNumber = a>b ? a : b;
    
    while (a%10==0 && b%10==0) {
        a = a/10;
        b = b/10;
    }
    while (a%2==0 && b%2==0) {
        a = a/2;
        b = b/2;
    }

    do {
        while (true) {
            if (a%greatestNumber==0 && b%greatestNumber==0) {
                greatestCommonDivisor = greatestNumber;
                break;
            } else {
                greatestNumber--;
            }
            if (greatestNumber <= 0) {
                greatestCommonDivisor = 1;
                break;
            }
        }
        a = a/greatestCommonDivisor;
        b = b/greatestCommonDivisor;
        } while  (greatestCommonDivisor != 1);
        numerator = a;
        denominator = b;
}
template <typename Number>
void Fraction::add(Number x) {
    int xint = (int)x;
    int zeros = 0;
    if (xint-x != 0){
        std::string tempString = std::to_string(x-xint);
        zeros = tempString.size();
    }
    x = x*denominator;
    Number xdenom = std::pow(10,zeros) * denominator;
    numerator = numerator * (xdenom/denominator);
    denominator = denominator * (xdenom/denominator);
    numerator = numerator + x;
    simplify();

}
template <typename Number>
void Fraction::sub(Number x) {
    int xint = (int)x;
    int zeros = 0;
    if (xint-x != 0){
        std::string tempString = std::to_string(x-xint);
        zeros = tempString.size();
    }
    x = x*denominator;
    Number xdenom = std::pow(10,zeros) * denominator;
    numerator = numerator * (xdenom/denominator);
    denominator = denominator * (xdenom/denominator);
    numerator = numerator - x;
    simplify();

}
void Fraction::add(Fraction x) {
    x.numerator = x.numerator*denominator;
    int xdenom = x.denominator * denominator;
    numerator = numerator * (xdenom/denominator);
    denominator = denominator * (xdenom/denominator);
    numerator = numerator + x.numerator;
    simplify();

}
void Fraction::sub(Fraction x) {
    x.numerator = x.numerator*denominator;
    int xdenom = x.denominator * denominator;
    numerator = numerator * (xdenom/denominator);
    denominator = denominator * (xdenom/denominator);
    numerator = numerator - x.numerator;
    simplify();

}
std::string Fraction::display() {
    simplify();
    std::string output = std::to_string(numerator);
    output += '/';
    output += std::to_string(denominator);
    return output;
}
template <typename Number>
Fraction Fraction::operator + (Number pos) {
    Fraction toReturn(numerator,denominator);
    toReturn.add(pos);
    return toReturn;
}
template <typename Number>
Fraction Fraction::operator - (Number pos) {
    Fraction toReturn(numerator,denominator);
    toReturn.sub(pos);
    return toReturn;
}
template <typename Number>
Fraction Fraction::operator / (Number pos) {
    Fraction toReturn(numerator,denominator);
    toReturn.divide(pos);
    return toReturn;
}
template <typename Number>
Fraction Fraction::operator * (Number pos) {
    Fraction toReturn(numerator,denominator);
    toReturn.multiply(pos);
    return toReturn;
}

std::ostream& operator<<(std::ostream& os, const Fraction& frac);
std::istream& operator>>(std::istream& is, Fraction& frac);

std::ostream& operator<<(std::ostream& os, const Fraction& frac) {
    os << frac.numerator << "/" << frac.denominator;
    return os;
}

std::istream& operator>>(std::istream& is, Fraction& frac) {
is>> frac.numerator >> frac.denominator;
return is;
}
}

fractionClass.h is

#include <iostream>
#include <cmath>
#include <string>
#include <algorithm>
#ifndef FRACTION_H
#define FRACTION_H
namespace fraction {

    class Fraction {
    private:
        int numerator;
        int denominator;
    public:
        Fraction(int x, int y);
        template <typename Number>
        Fraction(Number x);
        Fraction();
        double getDecimal();
        template <typename Number>
        void multiply(Number x);
        void multiply(Fraction x);
        template <typename Number>
        void divide(Number x);
        void divide(Fraction x);
        void simplify();
        template <typename Number>
        void add(Number x);
        template <typename Number>
        void sub(Number x);
        void add(Fraction x);
        void sub(Fraction x);
        std::string display();
        template <typename Number>
        Fraction operator + (Number pos);
        template <typename Number>
        Fraction operator - (Number pos);
        template <typename Number>
        Fraction operator / (Number pos);
        template <typename Number>
        Fraction operator * (Number pos);

        friend std::ostream& operator<<(std::ostream& os, const Fraction& frac);
        friend std::istream& operator>>(std::istream& is, Fraction& frac);
    };
    std::ostream& operator<<(std::ostream& os, const Fraction& frac);

    std::istream& operator>>(std::istream& is, Fraction& frac);
}
#endif

It is my first time messing with header files, this code does compile when run in the same space. I am working in macOS but could use windows if it fixes the problem. This code is meant to be a fraction class of sorts, it is still being made but it grew too large, and so I wanted to use multiple files. Can you show me an example of how you would fix this? It would be greatly appreciated. Thank you. The problem was as someone told me templates must be implemented in the header file, and so I have tried, however I can't manage to use them, can Someone show me an example of how you can implement the templates here. Btw I know the templates are the problem, because I removed them and It worked perfectly, however I do not want to write every single function for each data type.

VoidNull
  • 9
  • 4
  • 3
    What @igor-tandetnik probably want to express through closing your question, is that you need to implement template members inside the header. For this, you can cut-paste the implementation from the .cpp to the bottom of the .h He probably forgot to kindly express his intention (considering the OP is new in this comunity). I would also remind him that the question (even if the answer is very similar), is very different, and googling what the OP has in mind, is not very likely to show the linked answer. – Adrian Maire Sep 26 '20 at 20:55

0 Answers0