简体   繁体   中英

C++ I/O stream overload: How to implement friend overload, for 3 different classes, of the same 4 i/o functions in the same header?

I have a simple OpenGL project. Its structure is pretty straightforward:

Figure.h (down below) -> TFigureMatrix.h (template to operate figures) -> Cluster.h (sth like submenu to organise all the big functions) -> Source.cpp (console menu)

Figure.h:

#pragma once

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <time.h>
#include <iomanip>

#define RND1 (GLfloat)((rand() % 101)/500.)
#define RND2 (GLfloat)((rand() % 151-75)/100.)
#define RND3 (GLfloat)(rand() % 361)
#define SQR(x) ((x)*(x))
#define Len2(i, j) sqrt(SQR(Fig[i*3] - Fig[j*3]) + SQR(Fig[1+i*3] - Fig[1+j*3]))
#define MIN_val 0.005

class Square
{
    GLfloat Fig[18] = {
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,

        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f
    };
public:
    inline GLfloat S() { return SQR(Fig[3]); };
    inline GLfloat P() { return Fig[3] * 4; };
    inline GLfloat D() {
        return sqrt(
            SQR((Fig[0] + Fig[3] + Fig[6] + Fig[9]) / 4. + Fig[12]) +
            SQR((Fig[1] + Fig[4] + Fig[7] + Fig[10]) / 4. + Fig[13]) +
            SQR((Fig[2] + Fig[5] + Fig[8] + Fig[11]) / 4. + Fig[14]));
    };
    inline GLfloat* GetFig() { return Fig; };
    void Rnd() {
        memset(Fig, 0, sizeof(Fig));
        Fig[3] = RND1;
        Fig[12] = RND2; Fig[13] = RND2; Fig[14] = RND2;
        Fig[15] = RND3; Fig[16] = RND3; Fig[17] = RND3;
        Fig[7] = Fig[3]; Fig[9] = Fig[3]; Fig[10] = Fig[3];;
    };

    friend std::istream &operator >> (std::istream &, Square &);
    friend std::ostream &operator << (std::ostream &, Square &);
    friend std::ifstream &operator >> (std::ifstream &, Square &);
    friend std::ofstream &operator << (std::ofstream &, Square &);
};
class Rectang
{
    GLfloat Fig[18] = {
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f
    };
public:
    inline GLfloat S() { return Fig[3] * Fig[7]; };
    inline GLfloat P() { return (Fig[3] + Fig[7]) * 2; };
    inline GLfloat D() {
        return sqrt(
            SQR((Fig[0] + Fig[3] + Fig[6] + Fig[9]) / 4. + Fig[12]) +
            SQR((Fig[1] + Fig[4] + Fig[7] + Fig[10]) / 4. + Fig[13]) +
            SQR((Fig[2] + Fig[5] + Fig[8] + Fig[11]) / 4. + Fig[14]));
    };
    inline GLfloat* GetFig() { return Fig; };
    void Rnd() {
        memset(Fig, 0, sizeof(Fig));
        Fig[3] = RND1; Fig[7] = RND1;
        Fig[12] = RND2; Fig[13] = RND2; Fig[14] = RND2;
        Fig[15] = RND3; Fig[16] = RND3; Fig[17] = RND3;
        Fig[9] = Fig[3]; Fig[10] = Fig[7];
    };
    friend std::istream &operator >> (std::istream &, Rectang &);
    friend std::ostream &operator << (std::ostream &, Rectang &);
    friend std::ifstream &operator >> (std::ifstream &, Rectang &);
    friend std::ofstream &operator << (std::ofstream &, Rectang &);
};
class Triangle
{
    GLfloat Fig[15] = {
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f,
        0.0f,0.0f,0.0f
    };
public:
    inline GLfloat P() { return Len2(0, 1) + Len2(0, 2) + Len2(1, 2); };
    inline GLfloat S() { GLfloat hP = P() / 2.0f; return sqrt(hP*(hP - Len2(0, 1))*(hP - Len2(0, 2))*(hP - Len2(1, 2))); };
    inline GLfloat D() {
        return sqrt(
            SQR((Fig[0] + Fig[3] + Fig[6]) / 3. + Fig[9]) +
            SQR((Fig[1] + Fig[4] + Fig[7]) / 3. + Fig[10]) +
            SQR((Fig[2] + Fig[5] + Fig[8]) / 3. + Fig[11]));
    };
    inline GLfloat* GetFig() { return Fig; };
    void Rnd() {
        memset(Fig, 0, sizeof(Fig));
        Fig[3] = RND1; Fig[6] = RND1; Fig[7] = RND1;
        Fig[9] = RND2; Fig[10] = RND2; Fig[11] = RND2;
        Fig[12] = RND3; Fig[13] = RND3; Fig[14] = RND3;
    };
    friend std::istream &operator >> (std::istream &, Triangle &);
    friend std::ostream &operator << (std::ostream &, Triangle &);
    friend std::ifstream &operator >> (std::ifstream &, Triangle &);
    friend std::ofstream &operator << (std::ofstream &, Triangle &);
};

std::istream &operator >> (std::istream &stream, Square &obj) {
    memset((void*)obj.Fig, 0, sizeof(obj.Fig));
    stream >> obj.Fig[3] >> obj.Fig[7] >> obj.Fig[9] >> obj.Fig[10]
        >> obj.Fig[12] >> obj.Fig[13] >> obj.Fig[14]
        >> obj.Fig[15] >> obj.Fig[16] >> obj.Fig[17];
    return stream;
};
std::ostream &operator << (std::ostream &stream, Square &obj) {
    stream << "\n/(x: " << obj.Fig[3] << ")";
    return stream;
};
std::ifstream &operator >> (std::ifstream &stream, Square &obj) {
    char delim;
    memset((void*)obj.Fig, 0, sizeof(obj.Fig));
    stream >>
        delim >> obj.Fig[3] >>
        delim >> obj.Fig[7] >>
        delim >> obj.Fig[9] >>
        delim >> obj.Fig[10] >>
        delim >> obj.Fig[12] >> obj.Fig[13] >> obj.Fig[14] >>
        delim >> obj.Fig[15] >> obj.Fig[16] >> obj.Fig[17];
    return stream;
};
std::ofstream &operator << (std::ofstream &stream, Square &obj) {
    stream << "\n" << std::fixed << std::setprecision(3)
        << "\nx " << obj.Fig[3] << "\ny " << obj.Fig[7]
        << "\nx " << obj.Fig[9] << "\ny " << obj.Fig[10] << std::setprecision(2)
        << "\nm " << obj.Fig[12] << " " << obj.Fig[13] << " " << obj.Fig[14]
        << "\nr " << obj.Fig[15] << " " << obj.Fig[16] << " " << obj.Fig[17];
    return stream;
};

std::istream &operator >> (std::istream &stream, Rectang &obj) {
    memset((void*)obj.Fig, 0, sizeof(obj.Fig));
    stream >> obj.Fig[3] >> obj.Fig[7] >> obj.Fig[9] >> obj.Fig[10]
        >> obj.Fig[12] >> obj.Fig[13] >> obj.Fig[14]
        >> obj.Fig[15] >> obj.Fig[16] >> obj.Fig[17];
    return stream;
};
std::ostream &operator << (std::ostream &stream, Rectang &obj) {
    stream << "\n/(x: " << obj.Fig[3] << "|y: " << obj.Fig[7] << ")";
    return stream;
};
std::ifstream &operator >> (std::ifstream &stream, Rectang &obj) {
    char delim;
    memset((void*)obj.Fig, 0, sizeof(obj.Fig));
    stream >>
        delim >> obj.Fig[3] >>
        delim >> obj.Fig[7] >>
        delim >> obj.Fig[9] >>
        delim >> obj.Fig[10] >>
        delim >> obj.Fig[12] >> obj.Fig[13] >> obj.Fig[14] >>
        delim >> obj.Fig[15] >> obj.Fig[16] >> obj.Fig[17];
    return stream;
};
std::ofstream &operator << (std::ofstream &stream, Rectang &obj) {
    stream << "\n" << std::fixed << std::setprecision(3)
        << "\nx " << obj.Fig[3] << "\ny " << obj.Fig[7]
        << "\nx " << obj.Fig[9] << "\ny " << obj.Fig[10] << std::setprecision(2)
        << "\nm " << obj.Fig[12] << " " << obj.Fig[13] << " " << obj.Fig[14]
        << "\nr " << obj.Fig[15] << " " << obj.Fig[16] << " " << obj.Fig[17];
    return stream;
};

std::istream &operator >> (std::istream &stream, Triangle &obj) {
    memset((void*)obj.Fig, 0, sizeof(obj.Fig));
    stream >> obj.Fig[3] >> obj.Fig[6] >> obj.Fig[7]
        >> obj.Fig[9] >> obj.Fig[10] >> obj.Fig[11]
        >> obj.Fig[12] >> obj.Fig[13] >> obj.Fig[14];
    return stream;
};
std::ostream &operator << (std::ostream &stream, Triangle &obj) {
    stream << "\n/(x: " << obj.Fig[3] << "|x: " << obj.Fig[6] << " y: " << obj.Fig[7] << ")";
    return stream;
};
std::ifstream &operator >> (std::ifstream &stream, Triangle &obj) {
    char delim;
    memset((void*)obj.Fig, 0, sizeof(obj.Fig));
    stream >>
        delim >> obj.Fig[3] >>
        delim >> obj.Fig[6] >>
        delim >> obj.Fig[7] >>
        delim >> obj.Fig[9] >> obj.Fig[10] >> obj.Fig[11] >>
        delim >> obj.Fig[12] >> obj.Fig[13] >> obj.Fig[14];
    return stream;
};
std::ofstream &operator << (std::ofstream &stream, Triangle &obj) {
    stream << "\n" << std::fixed << std::setprecision(3)
        << "\nx " << obj.Fig[3] << "\nx " << obj.Fig[6]
        << "\ny " << obj.Fig[7] << std::setprecision(2)
        << "\nm " << obj.Fig[9] << " " << obj.Fig[10] << " " << obj.Fig[11]
        << "\nr " << obj.Fig[12] << " " << obj.Fig[13] << " " << obj.Fig[14];
    return stream;
};

The intention was to include this in another template class, which will process all the different figures here similarly. The problem is, it seems that i cannot make 2 or more similar friend overloads in one header:

std::istream &operator >> (std::istream &stream, Square &obj)
std::istream &operator >> (std::istream &stream, Rectang &obj)

In Figure.h, for example, he states 13 similar errors, like this one:

LNK2005 "class std::basic_ifstream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_ifstream<char,struct std::char_traits<char> > &,class Rectang &)" (??5@YAAAV?$basic_ifstream@DU?$char_traits@D@std@@@std@@AAV01@AAVRectang@@@Z) already defined in Cluster.obj

If i put those inside the classes, they are not seen, obviously, cause they must be friends. If i add const before all figure obj's it says, there is no overload for ">>/<< const whatever_type".

How do i solve this? (sry for any mistakes or if my question is already asked, haven't find it)

You're defining function in header. This defines the function in every .cpp file you include that header. Linker sees all those functions, doesnt know, that they are intended as the same function and drops you with an error.

Add inline keyword as quick fick.

inline std::ofstream &operator << (std::ofstream &stream, Triangle &obj) {
   ...
}

Or declare functions in header and define them in single .cpp file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM