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



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

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 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

现在,我在main.cpp文件中包含文件的顺序的场景,我首先包含了类list.h,然后包含了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;
}

现在,当我尝试在终端中使用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,这是一个非常轻松的项目,只是为了练习对类内文件的编写和读取如果你想看一看,并指导我正确的顺序来使用在类的另一个.h文件中定义的函数的友谊

github-srchttps://github.com/moji2013/student_projectV1.git

问题是,在当前的list.h中,有两个友元声明使用作用域解析运算符::来引用命名空间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. 在文件list.h中添加了命名空间friend_global_funcs。此命名空间包含operator<<operator>>的前向声明
  2. 在文件list.hfriend_global_funcs.cpp中为重载的operator<<的第二个参数添加了一个低级别常量
  3. 将文件friend_global_funcs.h的名称更改为friend_global.funcs.cpp,因为它包含实现

PS:我花了大约30分钟的时间从给定的github repo中创建了一个工作示例。你的程序中可能还有其他逻辑错误,我没有检查,因为回购相当大。我专注于手头的问题(即operator<<operator>>过载(。

list.h包括friend_global_funcs.h和friend_gglobal_funcs.hincludelist.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>>

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

最新更新