1

Ошибка:

1>------ Сборка начата: проект: OOP 2.3, Конфигурация: Debug Win32 ------  
1>Source.cpp  
1>Source.obj : error LNK2019: ссылка на неразрешенный внешний символ "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class Matrix<class division> &)" (??5@YAAAV?$basic_istream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$Matrix@Vdivision@@@@@Z) в функции _main  
1>Source.obj : error LNK2019: ссылка на неразрешенный внешний символ "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Matrix<class division> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$Matrix@Vdivision@@@@@Z) в функции _main  
1>D:\Лабы\OOP 2.3\Debug\OOP 2.3.exe : fatal error LNK1120: неразрешенных внешних элементов: 2  
1>Сборка проекта "OOP 2.3.vcxproj" завершена с ошибкой.  
========== Сборка: успешно: 0, с ошибками: 1, без изменений: 0, пропущено: 0 ==========

Программа:

#include <iostream>
#include <cmath>

using namespace std;

class division
{
private:
    int c, a, b;
    int NOD(int x, int y)
    {
        x = abs(x);
        y = abs(y);
        if (y == NULL) return x;
        return NOD(y, x % y);
    }
public:
    division(int c = 0, int num = 0, int dem = 1)
    {
        int nod = NOD(num, dem);
        int x = c * num + dem;
        if (x > 0 && dem > 0 || x < 0 && dem < 0)
        {
            this->a = abs(num) % abs(dem) / nod;
            this->b = abs(dem) / nod;
            this->c = c + abs(num) / abs(dem);
        }
        else if (x > 0 && dem < 0 || x < 0 && dem > 0)
        {
            this->a = abs(x) % abs(dem) / nod;
            this->b = abs(dem) / nod;
            this->c = -1 * abs(x) / abs(dem);
        }
    }
    bool operator >(int number) 
    {
        return c > number;
    }
    bool operator <=(division f) 
    {
        if (c <= f.c) {
            return true;
        }
        else if (a / b <= f.a / f.b)
        {
            return true;
        }
        return false;
    }
    int A()
    {
        return a;
    }
    int B()
    {
        return b;
    }
    int C()
    {
        return c;
    }
    division Input(int c, int a, int b)
    {
        return division(c, a, b);
    }
    division operator +(division& fraction)
    {
        int nod = NOD((c * a + b)*fraction.b + b * (fraction.c * fraction.a + fraction.b), b*fraction.b);
        return division(0, ((c * a + b)*fraction.b + b * (fraction.c * fraction.a + fraction.b)) / nod, (b*fraction.b) / nod);
    }
    division operator -(division& fraction)
    {
        int nod = NOD((c * a + b)*fraction.b - b * (fraction.c * fraction.a + fraction.b), b*fraction.b);
        return division(0, ((c * a + b)*fraction.b - b * (fraction.c * fraction.a + fraction.b)) / nod, (b*fraction.b) / nod);
    }
    division operator *(division& fraction)
    {
        int nod = NOD((c * a + b)*(fraction.c * fraction.a + fraction.b), b*fraction.b);
        return division(0, ((c * a + b)*(fraction.c * fraction.a + fraction.b)) / nod, (b*fraction.b) / nod);
    }
    friend istream& operator>>(istream& os, division& f) {
        os >> f.c >> f.a >> f.b;
        return os;
    }
    friend ostream& operator<<(ostream& os, division& f) {
        os << f.c << " " << f.a << "\\" << f.b;
        return os;
    }
};

template <typename T>
class Matrix
{
public:
    int n;
    int m;
    class wrong_size {};
    class wrong_count {};
    Matrix(int height = 3, int width = 4);
    Matrix(const Matrix& A);
    ~Matrix();
    void value(int i, int j, T val);
    Matrix& operator =(const Matrix& A);
    Matrix operator+(Matrix& A);
    Matrix operator-(Matrix& A);
    Matrix operator*(Matrix& A);
    T* operator[](int i);
    friend istream& operator >>(istream& input, Matrix& A);
    friend ostream& operator <<(ostream& output, Matrix& A);
private:
    T * * M;
};
template <typename T>
Matrix<T>::Matrix(int height, int width) : n(height), m(width)
{
    M = new T*[n];
    for (int i = 0; i < n; i++)
        M[i] = new T[m];
}
template <typename T>
Matrix<T>::Matrix(const Matrix& A) : n(A.n), m(A.m)
{
    M = new T*[n];
    for (int i = 0; i < n; i++)
        M[i] = new T[m];
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            M[i][j] = A.M[i][j];
}
template <typename T>
Matrix<T>::~Matrix()
{
    for (int i = 0; i < n; i++)
        delete[] M[i];

    delete[] M;
}
template <typename T>
void Matrix<T>::value(int i, int j, T val)
{
    M[i][j] = val;
}
template <typename T>
class Matrix<T>& Matrix<T>::operator=(const Matrix<T>& A)
{
    n = A.n;
    m = A.m;
    if (this != &A)
    {
        for (int i = 0; i < n; i++)
            delete[] M[i];
        delete[] M;
        M = new T*[n];
        for (int i = 0; i < n; i++)
            M[i] = new T[m];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                M[i][j] = A.M[i][j];
    }
    return *this;
}
template <typename T>
Matrix<T> Matrix<T>::operator+(Matrix& A)
{
    if (n == A.n && m == A.m)
    {
        Matrix X(n, m);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                X[i][j] = M[i][j] + A[i][j];
        return X;
    }
    else throw wrong_size();
}
template <typename T>
Matrix<T> Matrix<T>::operator-(Matrix& A)
{
    if (n == A.n && m == A.m)
    {
        Matrix X(n, m);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                X[i][j] = M[i][j] - A[i][j];
        return X;
    }
    else throw wrong_size();
}
template <typename T>
Matrix<T> Matrix<T>::operator*(Matrix& A)
{
    if (A.n == m)
    {
        Matrix X(A.n, m);

        for (int i = 0; i < A.n; i++)
            for (int j = 0; j < m; j++)
            {
                X[i][j] = 0;
                for (int k = 0; k < n; k++)
                    X.value(k, j, (M[k][j] * A[i][k]));
            }
        return X;
    }
    else throw wrong_count();
}
template <typename T>
T* Matrix<T>::operator[](int i)
{
    return M[i];
}
template <typename T>
istream& operator>>(istream& input, Matrix<T>& A)
{
    for (int i = 0; i < A.n; i++)
        for (int j = 0; j < A.m; j++)
            input >> A.M[i][j];
    return input;
}
template <typename T>
ostream& operator<<(ostream& output, Matrix<T>& A)
{
    for (int i = 0; i < A.n; i++) {
        for (int j = 0; j < A.m; j++)
            output << A[i][j] << " ";
        output << endl;
    }
    return output;
}

void Min(Matrix<division>&A) {
    division min = A[0][0];
    for (int i = 0; i < A.m; i++)
        for (int j = 0; j < A.n; j++)
            if (A[i][j] <= min)
                min = A[i][j];
    cout << min << endl;
}

int main()
{
    setlocale(LC_ALL, "Russian");
    try {
        int n1, m1;
        cout << "Введите n1 & m1: ";
        cin >> n1 >> m1;
        Matrix<division> M1(n1, m1);
        cin >> M1;

        int n2, m2;
        cout << "Введите n2 & m2: ";
        cin >> n2 >> m2;
        Matrix<division> M2(n2, m2);
        cin >> M2;

        Matrix<division> M3(n1,m2);

        M3 = M1 + M2;
        cout << "Сумма: " << endl << M3;

        M3 = M1 - M2;
        cout << "Разность: " << endl << M3;

        M3 = M1 * M2;
        cout << "Произведение: " << endl << M3;

        cout << "======================\nMin mas1:\n";
        Min(M1);
        cout << "======================\nMin mas2:\n";
        Min(M2);
        cout << "======================\nMin mas2:\n";

    }

    catch (Matrix<division>::wrong_size)
    {
        cout << "Вы ввели неправильный размер матриц." << endl;
    }
    catch (Matrix<division>::wrong_count)
    {
        cout << "Ошибка, во время вычисления" << endl;
    }

    system("pause");
    return 0;
}
entithat
  • 13,090
  • архитектура храмает. Подумайте об улучшении – AR Hovsepyan Apr 26 '18 at 18:59
  • Также https://ru.stackoverflow.com/questions/572501/%D0%94%D1%80%D1%83%D0%B7%D1%8C%D1%8F-%D0%B2-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BD%D0%BE%D0%BC-%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B5, https://ru.stackoverflow.com/questions/511272/%D0%94%D0%BE%D1%81%D1%82%D1%83%D0%BF-%D0%BA-%D0%BF%D1%80%D0%B8%D0%B2%D0%B0%D1%82%D1%83-%D1%87%D0%B5%D1%80%D0%B5%D0%B7-friend Этот вопрос уже много раз задавался. – AnT stands with Russia Apr 26 '18 at 19:25
  • @ARHovsepyan Для студента 1-го курса сложно понять, как лучше сделать – Eugene Rybalko Apr 26 '18 at 19:25
  • @AnT Я ведь не знал с какой стороны подойти к ошибке. Поэтому даже не понятно как задать поиск, если на то пошло. – Eugene Rybalko Apr 26 '18 at 19:28
  • Это нормально. В моем комментарии нет никакого упрека. Это стандартная практика на SO - отмечать и чистить дупликаты. – AnT stands with Russia Apr 26 '18 at 19:34
  • @Женя Рыбалко, я же не упрекал, а просто предложил подумать о улучшении – AR Hovsepyan Apr 26 '18 at 20:18

1 Answers1

0

Тута хитрый случай. Объявление friend операторов внутри класса объявляет нешаблонные операторы, которые и выбирает компилятор как более подходищие (по сравнению с шаблонными). А реализованы как раз шаблонные операторы. Правильное объявление должно соответствовать реализованным:

template<typename T_Inner>
friend istream& operator >>(istream& input, Matrix<T_Inner>& A);

template<typename T_Inner>
friend ostream& operator <<(ostream& output, Matrix<T_Inner>& A);

и да, второй параметр в оператор << должен быть ссылкой на константу:

template<typename T_Inner>
friend ostream& operator <<(ostream& output, Matrix<T_Inner> const & A);

А вообще предварительное объявление как friend внутри класса тут не к чему, так как содержимое матрицы можно вымести и так.

user7860670
  • 29,796
  • Если указывать во втором параметре ссылку на константу, то рушится опять же вся программа. Но вот без константного значения, работает все нормально – Eugene Rybalko Apr 26 '18 at 18:45
  • @ЖеняРыбалко Что значит рушится? Это оператор должен быть реализован так, чтобы принимать ссылку на константу. – user7860670 Apr 26 '18 at 18:48