将 .h(库)文件中的函数声明为类的友元

发布于 2025-01-11 02:50:45 字数 4405 浏览 0 评论 0原文

我正在为产品列表编写一个简单的类,我需要重载提取>>运算符和插入 <<操作符写入文件并从文件

Student_projectV1/list.h

#ifndef STUDENT_PROJECTV1_LIST
#define STUDENT_PROJECTV1_LIST


#include <fstream>



namespace list {

    class list {

        private:

            string name;
            int price;
            short quantity;


        public:

            ofstream ofs;
            ifstream ifs;


            // file_mutators
            void set_created_file () noexcept(false) ;
            void set_readable_file ();

            // constructors
            list() noexcept ( noexcept ( set_created_file() ) )  ;

            list ( string  , int , short  ) noexcept(false) ;
            list ( class list &) noexcept ( noexcept ( set_created_file() ) ) ;

            // initialization to cover after construction of an obj
            void initialize ( string , int , short ) noexcept(false) ;

            // mutators
            void set_name ( string ) noexcept(false);
            void set_price ( int ) noexcept(false) ;
            void set_quantity ( short ) noexcept(false) ;


            // accessors

            string get_name ( ) const  noexcept;
            int get_price () const noexcept;
            int get_quantity () const noexcept;


            // Enqueries
            bool check_created_file () noexcept;
            bool check_opened_file();

            // destructor
            ~list();



            // friend global functions
            // overloaded operators

            friend ofstream & friend_global_funcs :: operator << ( ofstream & , class list::list &) ;
            friend ifstream &  friend_global_funcs :: operator >> ( ifstream & , class list::list &) ;


    };
}


#endif

中读取现在我计划将这两个重载函数的定义放在命名空间friend_global_funcs.h内的另一个 friend_global_funcs.h 文件

friend ofstream & friend_global_funcs :: operator << ( ofstream & , class list::list &) ;
friend ifstream &  friend_global_funcs :: operator >> ( ifstream & , class list::list &) ;

//
// Created by solo-l-ub on 2/27/22.
//

#ifndef STUDENT_PROJECTV1_FRIEND_GLOBAL_FUNCS_H
#define STUDENT_PROJECTV1_FRIEND_GLOBAL_FUNCS_H





namespace friend_global_funcs {

    ofstream & operator<< (ofstream &ofs, class list::list &l)  {

        if (!l.check_created_file())
            throw new file_missing::file_missing(
                    "can not write info to file something wrong with acquiring file in constructor of obj \n");


        ofs << l.name() << "\t" << l.price << "\t" << l.quantity << "\n";

        return ofs;

    }


    ifstream & operator>>(ifstream &ifs, list :: list &l) {

        l.set_readable_file();

        if (!l.check_opened_file())
            throw new file_missing::file_missing(
                    "can't retrieve data cuz file is not associated with obj currently I'm in operated >> overloaded fuc \n");


        ifs >> l.name >> l.price >> l.quantity;

        return ifs;
    }

}

#endif //STUDENT_PROJECTV1_FRIEND_GLOBAL_FUNCS_H

我的场景在 main.cpp 文件中包含文件的顺序我首先包含类 list.h,然后包含 friend_global_funcs.h 文件

main.cpp



#include <iostream>
using namespace std;

// using namespaces


// classes
#include "file_missing.h"
#include "empty.h"
#include "list.h"


// libraries
#include "friend_global_funcs.h"

int main() {



    //////////////////////////////////////

    return 0;
}


现在,当我尝试使用 g++ 在终端中编译

g++ main.cpp -o out

时,我收到错误,即 list.h 中的重载函数未声明,即使我已使用范围解析运算符来告诉编译器确切的位置寻找函数 friend_global_funcs::operator <<

g++ 终端错误

In file included from main.cpp:33:
list.h:64:31: error: ‘friend_global_funcs’ has not been declared
   64 |             friend ofstream & friend_global_funcs :: operator << ( ofstream & , class list::list &) ;

现在我已经上传了我的项目,这是一个非常非常轻的项目,只是为了练习从类内部到 github 的文件写入和读取 如果您想看一下它并指导我使用在类

github src 中的另一个 .h 文件中定义的函数的友谊的正确顺序 https://github.com/moji2013/student_projectV1.git

I’m writing a simple class for list of products and there I need to overload both extraction >> operator and insertion << operator to write into file and read from file

student_projectV1/list.h

#ifndef STUDENT_PROJECTV1_LIST
#define STUDENT_PROJECTV1_LIST


#include <fstream>



namespace list {

    class list {

        private:

            string name;
            int price;
            short quantity;


        public:

            ofstream ofs;
            ifstream ifs;


            // file_mutators
            void set_created_file () noexcept(false) ;
            void set_readable_file ();

            // constructors
            list() noexcept ( noexcept ( set_created_file() ) )  ;

            list ( string  , int , short  ) noexcept(false) ;
            list ( class list &) noexcept ( noexcept ( set_created_file() ) ) ;

            // initialization to cover after construction of an obj
            void initialize ( string , int , short ) noexcept(false) ;

            // mutators
            void set_name ( string ) noexcept(false);
            void set_price ( int ) noexcept(false) ;
            void set_quantity ( short ) noexcept(false) ;


            // accessors

            string get_name ( ) const  noexcept;
            int get_price () const noexcept;
            int get_quantity () const noexcept;


            // Enqueries
            bool check_created_file () noexcept;
            bool check_opened_file();

            // destructor
            ~list();



            // friend global functions
            // overloaded operators

            friend ofstream & friend_global_funcs :: operator << ( ofstream & , class list::list &) ;
            friend ifstream &  friend_global_funcs :: operator >> ( ifstream & , class list::list &) ;


    };
}


#endif

now I plan to place the definition of these two overloaded functions in another friend_global_funcs.h file inside a namespace

friend ofstream & friend_global_funcs :: operator << ( ofstream & , class list::list &) ;
friend ifstream &  friend_global_funcs :: operator >> ( ifstream & , class list::list &) ;

friend_global_funcs.h

//
// Created by solo-l-ub on 2/27/22.
//

#ifndef STUDENT_PROJECTV1_FRIEND_GLOBAL_FUNCS_H
#define STUDENT_PROJECTV1_FRIEND_GLOBAL_FUNCS_H





namespace friend_global_funcs {

    ofstream & operator<< (ofstream &ofs, class list::list &l)  {

        if (!l.check_created_file())
            throw new file_missing::file_missing(
                    "can not write info to file something wrong with acquiring file in constructor of obj \n");


        ofs << l.name() << "\t" << l.price << "\t" << l.quantity << "\n";

        return ofs;

    }


    ifstream & operator>>(ifstream &ifs, list :: list &l) {

        l.set_readable_file();

        if (!l.check_opened_file())
            throw new file_missing::file_missing(
                    "can't retrieve data cuz file is not associated with obj currently I'm in operated >> overloaded fuc \n");


        ifs >> l.name >> l.price >> l.quantity;

        return ifs;
    }

}

#endif //STUDENT_PROJECTV1_FRIEND_GLOBAL_FUNCS_H

now My scenario of the order of including files in main.cpp file I’ve included first the class list.h and then the friend_global_funcs.h file

main.cpp



#include <iostream>
using namespace std;

// using namespaces


// classes
#include "file_missing.h"
#include "empty.h"
#include "list.h"


// libraries
#include "friend_global_funcs.h"

int main() {



    //////////////////////////////////////

    return 0;
}


now when I try to compile in terminal using g++

g++ main.cpp -o out

I get the error that overloaded functions in list.h are not declared even though I’ve used the scope resolution operator to tell compiler to exactly where to look for the function friend_global_funcs :: operator <<

g++ terminal error

In file included from main.cpp:33:
list.h:64:31: error: ‘friend_global_funcs’ has not been declared
   64 |             friend ofstream & friend_global_funcs :: operator << ( ofstream & , class list::list &) ;

now I’ve uploaded my project which is a very very light project just to practice writing and reading to files from inside classes to github
in case you want to take a look at it and guide me the proper sequence to use the friendship of a function which is defined in another .h file in a class

github src
https://github.com/moji2013/student_projectV1.git

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

姐不稀罕 2025-01-18 02:50:45

问题是,在当前的 list.h 中,您有 2 个使用范围解析运算符友元声明 :: 引用命名空间 friend_global_funcs 内的 operator<<operator>>。在这些友元声明时,编译器不知道命名空间 friend_global_funcs

因此,要解决这个问题,您需要告诉编译器有一个名为 friend_global_funcs 的命名空间,其中包含 operator<<的声明>operator>> 如下所示(工作中演示):

list.h

#ifndef STUDENT_PROJECTV1_LIST
#define STUDENT_PROJECTV1_LIST


#include <fstream>
#include <string>
namespace list {
    class list;
}
namespace friend_global_funcs {

    std::ofstream & operator << ( std::ofstream & , const list::list &) ; //const added here and keyword class removed from second parameter
    std::ifstream & operator >> ( std::ifstream & , list::list &) ;//keyword class removed from second parameter
}

namespace list {

    class list {

        private:

            std::string name;
            int price;
            short quantity;


        public:

            std::ofstream ofs;
            std::ifstream ifs;


            // file_mutators
            void set_created_file () noexcept(false) ;
            void set_readable_file ();

            // constructors
            list() noexcept ( noexcept ( set_created_file() ) )  ;

            list ( std::string  , int , short  ) noexcept(false) ;
            list ( class list &) noexcept ( noexcept ( set_created_file() ) ) ;

            // initialization to cover after construction of an obj
            void initialize ( std::string , int , short ) noexcept(false) ;

            // mutators
            void set_name ( std::string ) noexcept(false);
            void set_price ( int ) noexcept(false) ;
            void set_quantity ( short ) noexcept(false) ;


            // accessors

            std::string get_name ( ) const  noexcept;
            int get_price () const noexcept;
            int get_quantity () const noexcept;


            // Enqueries
            bool check_created_file () const noexcept;//const added here
            bool check_opened_file();

            // destructor
            ~list();



            // friend global functions
            // overloaded operators

            friend std::ofstream & friend_global_funcs :: operator << ( std::ofstream & , const list &) ;//const added here
            friend std::ifstream &  friend_global_funcs :: operator >> ( std::ifstream & , list &) ;


    };
    
}

#endif

list.cpp

#include "list.h"
#include"empty.h"
#include "file_missing.h"
namespace list{
// constructors
list :: list () noexcept ( noexcept ( set_created_file() ) )  {
    // give 'em a valid obj
    // ,and a most common one
    name = "not_set" , price = 1 , quantity = 1;

    // not sure weather to call the
    set_created_file();
    // or simply call this
//    ofs.open("list.txt", ios::app);
}

list :: list ( std::string name , int price , short quantity ) noexcept(false) {

    set_name ( name );
    set_price ( price );
    set_quantity ( quantity );

    set_created_file();
}

list :: list ( class list &r ) noexcept ( noexcept ( set_created_file() ) )  {

    name = r.name;
    price = r.price;
    quantity = r.quantity;

    // how to copy file location then?

//    ofs = r.ofs;
    set_created_file();
}
////


// initialization to cover after construction of an obj
void list :: initialize ( std::string name , int price , short quantity ) {
    set_name ( name );
    set_price ( price );
    set_quantity ( quantity );
    set_created_file();
}
////

// mutators
void list :: set_name ( std::string name ) noexcept(false) {

    if ( name.empty() )
        throw new empty::empty ( "name can not be left out enter something \n");

    (*this).name = name;
}

void list :: set_price ( int price )  noexcept(false) {

    if ( !price )
        throw new empty :: empty ( "price can not be zero \n" );

    (*this).price = price;
}

void list :: set_quantity ( short quantity ) noexcept(false) {

    if ( !quantity )
        throw new empty :: empty ( "quantity can not be zero \n" );

    (*this).quantity = quantity;
}

/////


// file mutators
void list :: set_created_file () noexcept(false) {

    if ( !ofs.is_open() )
        ofs.open("student_list_file.txt", std::ios::app);

    if ( !ofs.is_open() )
        throw new file_missing :: file_missing ( "file couldn't be created or opened \n" );

}

void list :: set_readable_file () {

    if ( !ifs.is_open() )
        ifs.open ( "student_list_file.txt" );

    if ( !ifs.is_open() )
        throw new file_missing :: file_missing ( "file couldn't be opened by set_readable_file function \n" );

}



////


// accessors
std::string list :: get_name () const noexcept {
    return name;
}
int list :: get_price () const  noexcept {
    return price;

}
int list :: get_quantity () const  noexcept {
    return quantity;
}

///

// enqueries
bool list :: check_created_file () const noexcept{

    return ofs.is_open();
}


bool list :: check_opened_file (){

    return ifs.is_open();
}


// destructive
list :: ~list() {
    // release resources
    // close file
    // close connection
    // release heap memory

    ofs.close();
    ifs.close();

}
}

friend_global_funcs.cpp


#include "list.h"
#include "file_missing.h"
#include "empty.h"
namespace friend_global_funcs {

    std::ofstream & operator<< (std::ofstream &ofs, const list::list &l)  { //const added here

        if (!l.check_created_file())
            throw new file_missing::file_missing(
                    "can not write info to file something wrong with acquiring file in constructor of obj \n");


        ofs << l.name << "\t" << l.price << "\t" << l.quantity << "\n"; //changed l.name() to l.name

        return ofs;

    }


    std::ifstream & operator>>(std::ifstream &ifs, list :: list &l) {

        l.set_readable_file();

        if (!l.check_opened_file())
            throw new file_missing::file_missing(
                    "can't retrieve data cuz file is not associated with obj currently I'm in operated >> overloaded fuc \n");


        ifs >> l.name >> l.price >> l.quantity;

        return ifs;
    }

}

工作演示

我所做的一些更改包括:

  1. 在文件内添加了命名空间 friend_global_funcs list.h。此命名空间包含operator<<operator>> 的前向声明。
  2. 在文件 list.hfriend_global_funcs.cpp 内重载的 operator<< 的第二个参数添加了一个低级常量。
  3. 将文件 friend_global_funcs.h 的名称更改为 friend_global.funcs.cpp,因为它包含实现。

PS:我花了大约 30 分钟从您给定的 github 存储库创建一个工作示例。您的程序中可能存在其他我尚未检查的逻辑错误,因为存储库相当大。我专注于手头的问题(即重载 operator<<operator>>)。

The problem is that in your current list.h, you have 2 friend declarations that uses the scope resolution operator :: to refer to operator<< and operator>> inside the namespace friend_global_funcs. And at the point of these friend declaration the compiler doesn't know about the namespace friend_global_funcs.

So to solve this you need to tell the compiler that there is a namespace called friend_global_funcs that has the declarations for operator<< and operator>> as shown below(Working Demo):

list.h

#ifndef STUDENT_PROJECTV1_LIST
#define STUDENT_PROJECTV1_LIST


#include <fstream>
#include <string>
namespace list {
    class list;
}
namespace friend_global_funcs {

    std::ofstream & operator << ( std::ofstream & , const list::list &) ; //const added here and keyword class removed from second parameter
    std::ifstream & operator >> ( std::ifstream & , list::list &) ;//keyword class removed from second parameter
}

namespace list {

    class list {

        private:

            std::string name;
            int price;
            short quantity;


        public:

            std::ofstream ofs;
            std::ifstream ifs;


            // file_mutators
            void set_created_file () noexcept(false) ;
            void set_readable_file ();

            // constructors
            list() noexcept ( noexcept ( set_created_file() ) )  ;

            list ( std::string  , int , short  ) noexcept(false) ;
            list ( class list &) noexcept ( noexcept ( set_created_file() ) ) ;

            // initialization to cover after construction of an obj
            void initialize ( std::string , int , short ) noexcept(false) ;

            // mutators
            void set_name ( std::string ) noexcept(false);
            void set_price ( int ) noexcept(false) ;
            void set_quantity ( short ) noexcept(false) ;


            // accessors

            std::string get_name ( ) const  noexcept;
            int get_price () const noexcept;
            int get_quantity () const noexcept;


            // Enqueries
            bool check_created_file () const noexcept;//const added here
            bool check_opened_file();

            // destructor
            ~list();



            // friend global functions
            // overloaded operators

            friend std::ofstream & friend_global_funcs :: operator << ( std::ofstream & , const list &) ;//const added here
            friend std::ifstream &  friend_global_funcs :: operator >> ( std::ifstream & , list &) ;


    };
    
}

#endif

list.cpp

#include "list.h"
#include"empty.h"
#include "file_missing.h"
namespace list{
// constructors
list :: list () noexcept ( noexcept ( set_created_file() ) )  {
    // give 'em a valid obj
    // ,and a most common one
    name = "not_set" , price = 1 , quantity = 1;

    // not sure weather to call the
    set_created_file();
    // or simply call this
//    ofs.open("list.txt", ios::app);
}

list :: list ( std::string name , int price , short quantity ) noexcept(false) {

    set_name ( name );
    set_price ( price );
    set_quantity ( quantity );

    set_created_file();
}

list :: list ( class list &r ) noexcept ( noexcept ( set_created_file() ) )  {

    name = r.name;
    price = r.price;
    quantity = r.quantity;

    // how to copy file location then?

//    ofs = r.ofs;
    set_created_file();
}
////


// initialization to cover after construction of an obj
void list :: initialize ( std::string name , int price , short quantity ) {
    set_name ( name );
    set_price ( price );
    set_quantity ( quantity );
    set_created_file();
}
////

// mutators
void list :: set_name ( std::string name ) noexcept(false) {

    if ( name.empty() )
        throw new empty::empty ( "name can not be left out enter something \n");

    (*this).name = name;
}

void list :: set_price ( int price )  noexcept(false) {

    if ( !price )
        throw new empty :: empty ( "price can not be zero \n" );

    (*this).price = price;
}

void list :: set_quantity ( short quantity ) noexcept(false) {

    if ( !quantity )
        throw new empty :: empty ( "quantity can not be zero \n" );

    (*this).quantity = quantity;
}

/////


// file mutators
void list :: set_created_file () noexcept(false) {

    if ( !ofs.is_open() )
        ofs.open("student_list_file.txt", std::ios::app);

    if ( !ofs.is_open() )
        throw new file_missing :: file_missing ( "file couldn't be created or opened \n" );

}

void list :: set_readable_file () {

    if ( !ifs.is_open() )
        ifs.open ( "student_list_file.txt" );

    if ( !ifs.is_open() )
        throw new file_missing :: file_missing ( "file couldn't be opened by set_readable_file function \n" );

}



////


// accessors
std::string list :: get_name () const noexcept {
    return name;
}
int list :: get_price () const  noexcept {
    return price;

}
int list :: get_quantity () const  noexcept {
    return quantity;
}

///

// enqueries
bool list :: check_created_file () const noexcept{

    return ofs.is_open();
}


bool list :: check_opened_file (){

    return ifs.is_open();
}


// destructive
list :: ~list() {
    // release resources
    // close file
    // close connection
    // release heap memory

    ofs.close();
    ifs.close();

}
}

friend_global_funcs.cpp


#include "list.h"
#include "file_missing.h"
#include "empty.h"
namespace friend_global_funcs {

    std::ofstream & operator<< (std::ofstream &ofs, const list::list &l)  { //const added here

        if (!l.check_created_file())
            throw new file_missing::file_missing(
                    "can not write info to file something wrong with acquiring file in constructor of obj \n");


        ofs << l.name << "\t" << l.price << "\t" << l.quantity << "\n"; //changed l.name() to l.name

        return ofs;

    }


    std::ifstream & operator>>(std::ifstream &ifs, list :: list &l) {

        l.set_readable_file();

        if (!l.check_opened_file())
            throw new file_missing::file_missing(
                    "can't retrieve data cuz file is not associated with obj currently I'm in operated >> overloaded fuc \n");


        ifs >> l.name >> l.price >> l.quantity;

        return ifs;
    }

}

Working Demo

Some of the changes that i made include:

  1. Added namespace friend_global_funcs inside file list.h. This namespace contains the forward declarations for the operator<< and operator>>.
  2. Added a low-level const to the second parameter of overloaded operator<< inside files list.h and friend_global_funcs.cpp.
  3. Changed the name of the file friend_global_funcs.h to friend_global.funcs.cpp since it contains implementation.

PS: It took me around 30 minutes to create a working example out of your given github repo. There may be other logical errors in your program that i haven't checked because the repo is quite big. I was focusing on the problem at hand(which was to overload operator<< and operator>>).

落花浅忆 2025-01-18 02:50:45

list.h 包含friend_global_funcs.h,friend_global_funcs.h 包含list.h。这是行不通的。 A 不能在 B 之前,而 B 也在 A 之前。标头防护可以防止无限递归,但最终会导致一个标头位于第一个,因此没有它所依赖的声明。

正确的解决方案是遵循以下顺序:

  • 声明 list::list
  • 声明 friend_global_funcs::operator<<friend_global_funcs::operator>>
  • 定义 list::list
  • 定义 friend_global_funcs::operator<<friend_global_funcs::operator>>

PS 如果您在头文件中定义函数,那么您应该将该函数设为内联,这样您就不会因包含非内联定义而意外违反定义规则分成多个翻译单元。您还应该考虑为什么要在头文件中定义函数。

list.h includes friend_global_funcs.h and friend_global_funcs.h includes list.h. This cannot work. A cannot be before B while B is also before A. The header guards prevent infinite recursion, but you end up with one header being first, and thus not having the declartions that it depends on.

A correct solution is to follow this order:

  • Declare list::list
  • Declare friend_global_funcs::operator<< and friend_global_funcs::operator>>
  • Define list::list
  • Define friend_global_funcs::operator<< and friend_global_funcs::operator>>

P.S. If you define a function in a header file, then you should make that function inline so that you don't accidentally violate one definition rule by including the non-inline definition into multiple translation units. You should also think about why you want to define the functions within a header file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文