You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++模板类fractionType的LNK2019未解析外部符号错误求助

问题:模板化fractionType类的LNK2019链接错误

我正在为作业实现模板化的fractionType类,将原cpp文件中无法模板化的代码移到header文件后,解决了大部分问题,但仍遗留两个LNK2019错误:提示ostream的operator<<和istream的operator>>为未解析外部符号,在main函数中被引用。若在fractiontype.h中包含main.cpp会引发大量如fractionType未声明等错误。

现有代码

main.cpp

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

using namespace std;

int main() {

    //Fraction1 and Fraction2 Objects
    fractionType<float> fraction1(2, 3);
    fractionType<float> fraction2(0, 0);

    //Grab first fraction from user
    cout << "Enter a fraction in the form a/b: ";
    cin >> fraction1;

    //Grab second fraction from user
    cout << "Enter another fraction in the form a/b: ";
    cin >> fraction2;

    //Operators
    cout << fraction1 << " + " << fraction2 << " = " << fraction1 + fraction2 << "\n";
    cout << fraction1 << " - " << fraction2 << " = " << fraction1 - fraction2 << "\n";
    cout << fraction1 << " * " << fraction2 << " = " << fraction1 * fraction2 << "\n";
    cout << fraction1 << " / " << fraction2 << " = " << fraction1 / fraction2 << "\n";

    //Checking true or false statements
    cout << "\n" << fraction1 << " == " << fraction2;

    if (fraction1 == fraction2) {

        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " != " << fraction2;

    if (fraction1 != fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " < " << fraction2;

    if (fraction1 < fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " <= " << fraction2;

    if (fraction1 <= fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " > " << fraction2;

    if (fraction1 > fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " >= " << fraction2;

    if (fraction1 >= fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    return 0;

}

fractiontype.h

#ifndef H_fraction
#define H_fraction

#include <iostream>

using namespace std;

template <class T>
class fractionType
{

    //overload the stream insertion and extraction operators

    friend ostream& operator<<(ostream&, const fractionType<T>&);

    friend istream& operator>>(istream&, fractionType<T>&);

public:

    //overload the assignment operator

    const fractionType<T>& operator=(const fractionType<T>&);


    //constructors

    fractionType();

    fractionType(const fractionType<T>&);

    fractionType(const float&, const float&);



    //desctructor

    ~fractionType();


    //oveload the relational operators

    bool operator==(const fractionType<T>&) const;

    bool operator!=(const fractionType<T>&) const;

    bool operator<=(const fractionType<T>&) const;

    bool operator<(const fractionType<T>&) const;

    bool operator>=(const fractionType<T>&) const;

    bool operator>(const fractionType<T>&) const;


    //overload the arithemetic operators

    fractionType<T> operator+(const fractionType<T>&);

    fractionType<T> operator-(const fractionType<T>&);

    fractionType<T> operator*(const fractionType<T>&);

    fractionType<T> operator/(const fractionType<T>&);




private:
    T numenator;      //variable to store the numerator
    T denominator;    //variable to store the denominator

};

template <class T>
fractionType<T>::fractionType(const float& nu, const float& de) {

    numenator = nu;

    if (de == 0) {
        cout << "\n\tInvalid demoninator. " << "Default value considered for denominator. ";

        denominator = 1;
    }
    else {

        denominator = de;
    }
}//end function fractionType


// Default constructor
template <class T>
fractionType<T>::fractionType() {

    numenator = 0;
    denominator = 1;
}

// copy constructor
template <class T>
fractionType<T>::fractionType(const fractionType<T>& rightFraction) {

    numenator = rightFraction.numenator;
    denominator = rightFraction.denominator;
}//end copy constructor


//Desctructor
template <class T>
fractionType<T>::~fractionType() {


}//end Desctructor

//oveload the relational operators
template <class T>
bool fractionType<T>::operator==(const fractionType<T>& rightFraction) const {

    return ((numenator == rightFraction.numenator) && (denominator == rightFraction.denominator));

}//end function operator==

template <class T>
bool fractionType<T>::operator!=(const fractionType<T>& rightFraction) const {

    return ((numenator != rightFraction.numenator) || (denominator != rightFraction.denominator));

}//end function operator!=

template <class T>
bool fractionType<T>::operator<(const fractionType<T>& rightFraction) const {

    return ((numenator * rightFraction.denominator) < (denominator * rightFraction.numenator));

}//end function operator<

template <class T>
bool fractionType<T>::operator<=(const fractionType<T>& rightFraction) const {

    return ((numenator * rightFraction.denominator) <= (denominator * rightFraction.numenator));

}//end function operator<=

template <class T>
bool fractionType<T>::operator>(const fractionType<T>& rightFraction) const {

    return ((numenator * rightFraction.denominator) > (denominator * rightFraction.numenator));

}//end function operator>

template <class T>
bool fractionType<T>::operator>=(const fractionType<T>& rightFraction) const {

    return ((numenator * rightFraction.denominator) >= (denominator * rightFraction.numenator));

}//end function operator>=




//overload the arithemetic operators
template <class T>
fractionType<T> fractionType<T>::operator+(const fractionType<T>& rightFraction) {

    fractionType fractionHolder;

    fractionHolder.numenator = (numenator * rightFraction.denominator) + (denominator * rightFraction.numenator);
    fractionHolder.denominator = denominator * rightFraction.denominator;

    return fractionHolder;

}//end function operator+

template <class T>
fractionType<T> fractionType<T>::operator-(const fractionType<T>& rightFraction) {

    fractionType fractionHolder;

    fractionHolder.numenator = (numenator * rightFraction.denominator) - (denominator * rightFraction.numenator);
    fractionHolder.denominator = denominator * rightFraction.denominator;

    return fractionHolder;

}//end function operator-

template <class T>
fractionType<T> fractionType<T>::operator*(const fractionType<T>& rightFraction) {

    fractionType fractionHolder;

    fractionHolder.numenator = numenator * rightFraction.numenator;
    fractionHolder.denominator = denominator * rightFraction.denominator;

    return fractionHolder;

}//end function operator*

template <class T>
fractionType<T> fractionType<T>::operator/(const fractionType<T>& rightFraction) {

    fractionType fractionHolder;

    //check for validity for division
    if (rightFraction.numenator == 0 || rightFraction.denominator == 0) {

        fractionHolder.numenator = 0;
        fractionHolder.denominator = 1;

        cout << "Invalid to perform division.";

    }
    else {

        fractionHolder.numenator = numenator * rightFraction.denominator;
        fractionHolder.denominator = denominator * rightFraction.numenator;

    }//end else - if x

    return fractionHolder;

}//end function operator+


//overload the stream extraction operators
template <class T>
ostream& operator<<(ostream& osObject, const fractionType<T>& myFraction) {

    osObject << myFraction.numenator << "/" << myFraction.denominator;

    return osObject;

}//end function operator<<

template <class T>
istream& operator>>(istream& isObject, fractionType<T>& myFraction) {

    char ch;

    isObject >> myFraction.numenator >> ch >> myFraction.denominator;

    return isObject;

}//end function operator>>

#endif

问题原因

当前代码中,模板类fractionType的友元运算符operator<<和operator>>被声明为非模板函数,但实际定义的是模板版本。编译器会认为这是两组不同的函数,导致链接时找不到对应函数的实例化代码,从而抛出LNK2019错误。

解决方案

需要将友元运算符明确声明为模板函数,让编译器关联声明和定义。具体修改如下:

  1. 在类声明前,提前声明模板类和两个友元运算符;
  2. 在类内部的友元声明中,指定模板参数。

修正后的fractiontype.h

#ifndef H_fraction
#define H_fraction

#include <iostream>

using namespace std;

// 提前声明模板类和友元运算符
template <class T>
class fractionType;

template <class T>
ostream& operator<<(ostream&, const fractionType<T>&);

template <class T>
istream& operator>>(istream&, fractionType<T>&);

template <class T>
class fractionType
{
    // 明确声明友元为对应模板参数的函数
    friend ostream& operator<< <T>(ostream&, const fractionType<T>&);
    friend istream& operator>> <T>(istream&, fractionType<T>&);

public:
    const fractionType<T>& operator=(const fractionType<T>&);

    fractionType();
    fractionType(const fractionType<T>&);
    fractionType(const T&, const T&); // 将参数类型改为T,保持模板一致性

    ~fractionType();

    bool operator==(const fractionType<T>&) const;
    bool operator!=(const fractionType<T>&) const;
    bool operator<=(const fractionType<T>&) const;
    bool operator<(const fractionType<T>&) const;
    bool operator>=(const fractionType<T>&) const;
    bool operator>(const fractionType<T>&) const;

    fractionType<T> operator+(const fractionType<T>&);
    fractionType<T> operator-(const fractionType<T>&);
    fractionType<T> operator*(const fractionType<T>&);
    fractionType<T> operator/(const fractionType<T>&);

private:
    T numenator;
    T denominator;
};

template <class T>
fractionType<T>::fractionType(const T& nu, const T& de) { // 参数类型改为T
    numenator = nu;
    if (de == 0) {
        cout << "\n\tInvalid denominator. Default value considered for denominator. ";
        denominator = 1;
    } else {
        denominator = de;
    }
}

template <class T>
fractionType<T>::fractionType() {
    numenator = 0;
    denominator = 1;
}

template <class T>
fractionType<T>::fractionType(const fractionType<T>& rightFraction) {
    numenator = rightFraction.numenator;
    denominator = rightFraction.denominator;
}

template <class T>
fractionType<T>::~fractionType() {}

template <class T>
const fractionType<T>& fractionType<T>::operator=(const fractionType<T>& rightFraction) { // 补充赋值运算符实现
    if (this != &rightFraction) {
        numenator = rightFraction.numenator;
        denominator = rightFraction.denominator;
    }
    return *this;
}

template <class T>
bool fractionType<T>::operator==(const fractionType<T>& rightFraction) const {
    return ((numenator == rightFraction.numenator) && (denominator == rightFraction.denominator));
}

template <class T>
bool fractionType<T>::operator!=(const fractionType<T>& rightFraction) const {
    return !(*this == rightFraction); // 复用==运算符,减少冗余
}

template <class T>
bool fractionType<T>::operator<(const fractionType<T>& rightFraction) const {
    return ((numenator * rightFraction.denominator) < (denominator * rightFraction.numenator));
}

template <class T>
bool fractionType<T>::operator<=(const fractionType<T>& rightFraction) const {
    return (*this < rightFraction) || (*this == rightFraction); // 复用<和==运算符
}

template <class T>
bool fractionType<T>::operator>(const fractionType<T>& rightFraction) const {
    return !(*this <= rightFraction); // 复用<=运算符
}

template <class T>
bool fractionType<T>::operator>=(const fractionType<T>& rightFraction) const {
    return !(*this < rightFraction); // 复用<运算符
}

template <class T>
fractionType<T> fractionType<T>::operator+(const fractionType<T>& rightFraction) {
    fractionType fractionHolder;
    fractionHolder.numenator = (numenator * rightFraction.denominator) + (denominator * rightFraction.numenator);
    fractionHolder.denominator = denominator * rightFraction.denominator;
    return fractionHolder;
}

template <class T>
fractionType<T> fractionType<T>::operator-(const fractionType<T>& rightFraction) {
    fractionType fractionHolder;
    fractionHolder.numenator = (numenator * rightFraction.denominator) - (denominator * rightFraction.numenator);
    fractionHolder.denominator = denominator * rightFraction.denominator;
    return fractionHolder;
}

template <class T>
fractionType<T> fractionType<T>::operator*(const fractionType<T>& rightFraction) {
    fractionType fractionHolder;
    fractionHolder.numenator = numenator * rightFraction.numenator;
    fractionHolder.denominator = denominator * rightFraction.denominator;
    return fractionHolder;
}

template <class T>
fractionType<T> fractionType<T>::operator/(const fractionType<T>& rightFraction) {
    fractionType fractionHolder;
    if (rightFraction.numenator == 0 || rightFraction.denominator == 0) {
        fractionHolder.numenator = 0;
        fractionHolder.denominator = 1;
        cout << "Invalid to perform division.";
    } else {
        fractionHolder.numenator = numenator * rightFraction.denominator;
        fractionHolder.denominator = denominator * rightFraction.numenator;
    }
    return fractionHolder;
}

template <class T>
ostream& operator<<(ostream& osObject, const fractionType<T>& myFraction) {
    osObject << myFraction.numenator << "/" << myFraction.denominator;
    return osObject;
}

template <class T>
istream& operator>>(istream& isObject, fractionType<T>& myFraction) {
    char ch;
    isObject >> myFraction.numenator >> ch >> myFraction.denominator;
    return isObject;
}

#endif

额外优化说明

  • 把构造函数的参数类型从float改为模板参数T,保证模板类的通用性;
  • 补充了之前缺失的赋值运算符operator=实现;
  • 复用已实现的运算符简化其他关系运算符代码,减少冗余和出错概率;
  • 修正拼写错误:demoninator改为denominator。

内容的提问来源于stack exchange,提问作者2Silent4You

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 23:45:40