Search code examples
c++friend

C++: Member is inaccessible - using friend function to allow one class to modify another class member data


Okay, I have looked all over for an answer to this.

I am trying to set up a system where an object's private members can be modified only through two member functions of a separate class.

Here is the header content of the object to be modified, table.h:

#ifndef TABLE_H
#define TABLE_H

#include "party.h"

/*
Seats a party for their dining experience at the restaurant.
*/
class table
{
    friend void server::seatGuests(const table &, const party &);
    friend void server::cleanTable(const table &);

private:
    const unsigned int cap_; //guest capacity (shouldn't change)
    const unsigned int id_;  //table id (shouldn't change)
    mutable bool isTaken_;   //flag (changeable by friend functions)
    party *const group_;     //party seated at the table (starts off as null)

public:
    table::table(const unsigned int id, const unsigned int cap = 4); //ctor
    inline const unsigned int table::getCap() const { return cap_; }
    inline const unsigned int table::getId() const { return id_; }
    inline const bool table::isTaken() const { return isTaken_; }
    inline const party *const table::getParty() const { return group_; };
};

void server::seatGuests(const table &t, const party &p)
{
    t.isTaken_ = false;
}

#endif // TABLE_H

here is server.h:

class server : public employee
{
private:
public:
    explicit server::server();
    void server::seatGuests(const table &, const party &);
    void server::cleanTable(const table &);
};

...

I am getting the following error: member "table::isTaken_" (declared at line 17) is inaccessible

The server.h file is included in table.h indirectly, as party.h includes restaurant.h which includes server.h.

I tried putting this in table.h before:

class server;
namespace server {
   void server::seatGuests(const table &, const party &);
   void server::cleanTable(const table &);
}

But this just gave me more headaches, as the compiler would spit out something like, "class server has no member 'seatGuests' or 'cleanTable'", which I figured was due to some inclusion conflict. This conflict is why I've declared the function in the original server.h file and not in the table.h file.

That being said, sources I've read such as this one state that the implementation of the friend function should be in the class whose data is being modified, which is what I've done.

All that aside, the compiler still thinks the member data is not accessible. Can anyone see what I'm doing wrong here?

Let me know if you want me to post more code.

Thanks in advance.

EDIT

Apologies for the delay in posting the compiler output. Please see below:

> Executing task: clang++ -Wall -std=c++17 -stdlib=libc++ -o main.out /Users/ajm/Projects/restaurant/cpp/main/main.cpp -I/Users/ajm/Projects/restaurant/cpp/main/ -I/Users/ajm/Projects/restaurant/cpp/restaurant/ -I/Users/ajm/Projects/restaurant/cpp/people/ -I/Users/ajm/Projects/restaurant/cpp/people/workers/ -I/Users/ajm/Projects/restaurant/cpp/data/ --debug <

In file included from /Users/ajm/Projects/restaurant/cpp/main/main.cpp:1:
In file included from /Users/ajm/Projects/restaurant/cpp/main/simulation.h:4:
In file included from /Users/ajm/Projects/restaurant/cpp/restaurant/restaurant.h:4:
In file included from /Users/ajm/Projects/restaurant/cpp/restaurant/tablespace.h:4:
In file included from /Users/ajm/Projects/restaurant/cpp/restaurant/table.h:4:
In file included from /Users/ajm/Projects/restaurant/cpp/people/workers/server.h:4:
In file included from /Users/ajm/Projects/restaurant/cpp/people/workers/employee.h:5:
In file included from /Users/ajm/Projects/restaurant/cpp/main/../data/job.h:4:
/Users/ajm/Projects/restaurant/cpp/people/party.h:25:16: error: unknown type name 'restaurant'
    void start(restaurant &spot);
               ^
In file included from /Users/ajm/Projects/restaurant/cpp/main/main.cpp:1:
In file included from /Users/ajm/Projects/restaurant/cpp/main/simulation.h:4:
In file included from /Users/ajm/Projects/restaurant/cpp/restaurant/restaurant.h:4:
In file included from /Users/ajm/Projects/restaurant/cpp/restaurant/tablespace.h:4:
/Users/ajm/Projects/restaurant/cpp/restaurant/table.h:8:11: error: redefinition of 'server' as different kind of
      symbol
namespace server
          ^
/Users/ajm/Projects/restaurant/cpp/restaurant/table.h:7:7: note: previous definition is here
class server;
      ^
/Users/ajm/Projects/restaurant/cpp/restaurant/table.h:10:23: error: unknown type name 'table'
void seatGuests(const table &t, const party *const p);
                      ^
/Users/ajm/Projects/restaurant/cpp/restaurant/table.h:11:23: error: unknown type name 'table'
void cleanTable(const table &t);
                      ^
/Users/ajm/Projects/restaurant/cpp/restaurant/table.h:13:31: error: unknown type name 'table'
void server::seatGuests(const table &t, const party *const p)
                              ^
/Users/ajm/Projects/restaurant/cpp/restaurant/table.h:18:31: error: unknown type name 'table'
void server::cleanTable(const table &t)
                              ^
/Users/ajm/Projects/restaurant/cpp/restaurant/table.h:42:25: error: out-of-line declaration of 'seatGuests' does not
      match any declaration in 'server'
    friend void server::seatGuests(const table &t, const party *const p);
                        ^~~~~~~~~~
/Users/ajm/Projects/restaurant/cpp/restaurant/table.h:43:25: error: out-of-line declaration of 'cleanTable' does not
      match any declaration in 'server'
    friend void server::cleanTable(const table &t);
                        ^~~~~~~~~~
8 errors generated.
The terminal process terminated with exit code: 1

Solution

  • The declaration of server::seatGuests and server::cleanTable must appear before the friend declaration in table. #include "server.h" appears before the declaration of table so that should be enough right? Well, server includes table and table includes server so we have cyclic dependencies. To get around this, table should include server and server should forward declare table.

    // table.h
    
    #include "party.h"
    
    class table
    {
        friend void server::seatGuests(const table &, const party &);
        friend void server::cleanTable(const table &);
    };
    
    
    
    // server.h
    
    class table;
    class party;
    
    class server : public employee
    {
    public:
        explicit server();
        void seatGuests(const table &, const party &);
        void cleanTable(const table &);
    };
    

    Cyclic dependencies and friend declarations seem like bad design to me. Instead of using a forward declaration to get around this, you might want to rethink the design. Find a way to avoid the cycle and avoid the friend declarations. My answer is a workaround, not a solution.