-2

I am getting this error in my implementation:

struct bookdatabase::Bookdatabase::Book

class "bookdatabase::BookDatabase::Book" is inaccessible

None of the following solutions solved my problem:

Here's a picture of what visual studio has issue with in the .cpp file.

Here's a picture of the declaration in the header file.


Database.h

#include <string>
#include <vector>


#ifndef BOOKDATABASE_H
#define BOOKDATABASE_H

namespace bookdatabase {
    class BookDatabase {
    private:
        struct Book {
        private:
            std::string authorFirstName, authorLastName, authorFullName, bookTitle, pubDate;
        public:
            Book(const std::string &authFirst, const std::string &authLast, const std::string &title, const std::string &date);
            std::string getAuthor() const;
            std::string getBookTitle() const;
            std::string getPubDate() const;
            bool operator < (const Book &rhs) const;
            friend std::ostream& operator << (std::ostream& out, const bookdatabase::BookDatabase::Book& book);
        };
        void sortBooks();
        std::vector<Book>::iterator search(const std::string &title);
    public:
        BookDatabase();
        void printBookList();
        std::vector<Book> getDatabase() const;
        void removeBook(const std::string &title);

        void addBook(const std::string &authFirst, const std::string &authLast, const std::string &title, const std::string &date);
    private:
        std::vector<Book> database;
    };
}

#endif // BOOKDATABASE_H


Database.cpp

std::ostream & bookdatabase::operator<<(std::ostream & out, const bookdatabase::BookDatabase::Book & book) {
    out << authorFullName << ". " << bookTitle << ". " << pubDate;
    return out;
}


Am I having this issue because the Book class is a nested class?

James Patmon
  • 11
  • 1
  • 2
  • 3
    _"Am I having this issue because the `Book` class is a nested class?"_ No, you have that issue because it is a **`private`** nested class. – user0042 Dec 03 '17 at 02:52
  • @user0042 Thank you. It was my understanding that if the overloading operator is a friend of the class, it will have access to its private members. Does this not apply if the class is private? Does it make sense to make the operator a friend of the Database class instead to access the Book class? – James Patmon Dec 03 '17 at 03:56

2 Answers2

0

Alright, I seem to have discovered two things here which might be the problem you're having, one of which might be a bug in Visual Studio.

1. First of all, the thing which is not a bug

user0042, in his response to your post is right, operator<< being declared as friend in the struct Book results in the operator<< only being able to access private members of Book. But it cannot access Book itself, because Book is a private member of the enclosing BookDatabase class. Therefore you have to move the friend declaration to be outside Book and in BookDatabase.

Once you do that, operator<< can now access the private data member Book of BookDatabase. Note however that this does not give permission to operator<< to access the private data members of Book itself, namely authorFirstName, authorLastName, authorFullName, bookTitle, pubDate

2A. Now for the (what I believe to be) VS2017 scope operator bug

Let's say you have moved the friend declaration to BookDatabase, you still have to define the implementation in a specific way. The following two pieces of code should be equivalent ways to define the function in a Database.cpp file, but one of them doesn't work in VS2017 15.4.5.

It's ok to do

namespace bookdatabase {
    ostream& operator<<(ostream& out, const bookdatabase::BookDatabase::Book& book) {
    }
}  // OK

But not ok to do

ostream& bookdatabase::operator<<(ostream& out, const bookdatabase::BookDatabase::Book& book) {
}  // Visual Studio cannot access book

There seems to be an issue with Visual Studio's :: operator being able to obtain the friend property of a function.

So to answer your question: if you want your << operator overload to work you need to use the first method to define it in the .cpp implementation file.

2B. In fact I wrote a simple test program to show the VS2017 friend and :: bug

namespace my_namespace {
    class Test {
    private:
        struct Nested {};
    public:
        friend void func(Test::Nested&);
    };
    void func(Test::Nested&);
}

// DOES NOT COMPILE in VS2017 15.4.5, OK in GCC 6.3 and Clang 3.8.0
// VS2017 says Nested is inaccessible
void my_namespace::func(my_namespace::Test::Nested&) {
} 

But using namespace and brackets works

namespace my_namespace {
    class Test {
    private:
        struct Nested {};
    public:
        friend void func(Test::Nested&);
    };
    void func(Test::Nested&);
}

// changed to namespace + brackets, 
// COMPILES in VS2017 15.4.5, GCC 6.3 and Clang 3.8.0
namespace my_namespace {
    void func(my_namespace::Test::Nested&) {
    } 
}

Can someone please independently verify this?

I also posted a bug report on the Microsoft Developer Community

L.Y. Sim
  • 810
  • 6
  • 11
  • I moved the `operator<<` friend function to the Database class and removed the `bookdatabase` namespace scope resolution operator, opting to put the `operator<<` implementation within a namespace block instead (as shown in your post). Unfortunately, I still receive the error that the nested `Book` class is inaccessible. I think the only solution may be to make the nested `Book` class public. – James Patmon Dec 03 '17 at 13:06
  • That's strange, does yours compile fine? Mine compiles fine. Can you show me what has gone wrong? If you're trying to access the data members of `Book` from within the function body then you can't do that because the `operator<<` is not a friend of the Book struct. – L.Y. Sim Dec 03 '17 at 14:09
0

My answer for most operator << woes is to declare a member print() method that does the hard work and call it from operator <<. Usually I am happy for the print method to be public, and get rid of all the friend nastiness.

Gem Taylor
  • 5,381
  • 1
  • 9
  • 27