Friend functions not locating private members - c++

Please do not vote this down or mark this question as a duplicate for all of the answers that I have seen in other questions have not worked for me.
I created a class called contact that stores information about contacts. I was trying to implement an operator<< to output all information, so I had to make it a friend function. The problem with this is that I am unable to access any of the class's member functions. My code is as follows:
contact.h:
class contact {
long id;
string first;
string middle;
string last;
string company;
string home;
string office;
string email;
string mobile;
string street;
string city;
string state;
long zip;
string country;
vector<contact> affiliates;
public:
// output and input
friend ostream &operator<<(ostream &, const contact &);
};
contact.cpp:
...
ostream &operator<<(ostream &os, contact &rec) {
print(os, rec.id);
return os;
}
...
As you see, the function prototype is exactly the same, and I am not enclosing the class inside a namespace, which leaves no reason for the operator to be unable to access a member variable. Is this a problem with my prototype? Any help would be appreciated. Thanks.

The operator<< declaration and definition are actually not the same. In the friend declaration the second parameter is const contact &, and in the definition it's just contact&.
So the definition is actually unrelated to a friend declaration in the class, and defines another function which is not a friend of contact.

Related

what is the use of declaring the same struct 2 times for making a constructor? [duplicate]

This question already has answers here:
Class declaration with no definition in C++
(4 answers)
Closed 1 year ago.
I'm still learning and this code really confuse me.
struct Sales_data;
std::istream &read(std::istream &is, Sales_data &item);
struct Sales_data {
Sales_data::Sales_data(std::istream &is) {
read(is, *this);
}
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
That code basically use 2 struct Sales_data for making a single Sales_data(std::istream &is) {} constructor.
why not just do it like this?
struct Sales_data {
Sales_data(std::istream &is) {
read(is, *this);
}
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
struct Sales_data;
is a forward declaration that can be used to establish the prototype for the free function read.
after that it is implemented.
Since the constructor uses the read function it needs to be declared before the actual struct.
The code declares a read function and the declaration of this read function needs a declaration of the class:
struct Sales_data;
std::istream &read(std::istream &is, Sales_data &item);
This function is decalred before the class is defined, because the class definition is calling the function:
struct Sales_data {
Sales_data::Sales_data(std::istream &is) {
read(is, *this);
}
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
Somewhere down the line there must be a definition for read(std::istream&,Sales_data) otherwise there will be a linker error.
why not just do it like this? [...]
Because you need at least a declaration of read(std::istream&,Sales_data) to be able to call it. If you try your code you will get a compiler error because no read function has been declared.

std::ostream : class is inaccesible [C++]

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:
std::basic_ostream is inaccessible in C++
cannot access private members in friend ostream
My ostream and istream friend function can't access private class members
member of class inaccessible
Inaccessible Members ?
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?
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
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.

Declaring = and [] operators for a class on the header file, "must be a nonstatic member function" error

I've made a class Block and a struct coords and while implementing the operators i came up with the errors:
'coords operator[](const Block&, const size_t&)' must be a nonstatic member function
'bool operator=(Block&, const Block&)' must be a nonstatic member function
I've declared these 2 in the header file of the class Block as follows:
class Block
{
friend Block operator+(const Block&, const coords&);
friend Block operator+(const Block&, const Block&);
friend coords operator[](const Block&, const std::size_t&);
friend void operator+=(Block&, const coords&);
friend void operator+=(Block&, const Block&);
friend bool operator=(Block&, const Block&);
//...
};
Only the operators [] and = get this error, and I'm not sure why.
I've tried to change the return value and parameter types but it keeps getting the same problem.
Are these two operators special? Or is there an error on my declarations?
I've searched for ways to solve this problem, but couldn't find a suitable answer.
Thank you for the replies.
Not all operators can be overloaded using non-member functions. [] and = are two such operators. They can be overloaded only as member functions.
See http://en.cppreference.com/w/cpp/language/operators for more details.
Those operators cannot be declared as friends. Instead you should declare like this:
coords operator[](const std::size_t&);
bool operator=(const Block&);
Your operators are also not really following conventions. Operators += and = should be returning a Block& namely *this.
The reason is exactly what the error message says: those two have to be non-static member functions. Get rid of the friend from in front of them and remove the first argument.
Further, operator+= is usually implemented as a member function, too, although it doesn't have to be. But if it is, it gives you an easy way to implement operator+ without making it a friend.
#R Sahu's link was useful, showing that [] and = can no be declared as non-member, but it didn't really explain why.
#Baum mit aguen's link cleared some other questions too.
(Thanks for the information)
So, I adjusted my code to this new information as follows:
Block.h
class Block
{
public:
//...
coords* operator[](size_t);
Block operator=(Block);
//...
};
Block.cpp
//...
coords* Block::operator[](size_t index)
{
if(index >= 0 && index < block.size())
return &block.at(index);
coords *tmp = new coords(-1, -1);
return tmp;
}
Block Block::operator=(Block b2)
{
block.empty();
block.reserve(b2.block.size());
append(b2.block);
return *this;
}
//...
This way you can call *(*b1)[0] = c1; being Block* b1 and coords c1.
The friend modifier is useful for other types of implementations, although I only realized after that the implementation of inline had to be done in the header file, not on the cpp.
Block.h
class Block
{
public:
//...
friend std::ostream& operator<<(std::ostream&, const Block&);
friend std::ostream& operator<<(std::ostream&, Block&);
//...
};
inline std::ostream& operator<<(std::ostream& out, const Block& b)
{
// do something
return out;
};
inline std::ostream& operator<<(std::ostream& out, Block& b)
{
// do something
return out;
};
In this case, you need to pass the "this" parameter has to be passed to the function also as these are non-member functions and should be implemented outside the class, in the header file.
I hope this helps, good coding everyone.

C++ overloading operator<<

I'm trying to overload the << operator for a class to emulate toString() in Java. I have a NumExpr class, and has private variable number that I want to output. so here they are:
NumExpr::NumExpr( string n ) {
number = atoi( n.c_str() );
}
string NumExpr::name() {
return "num";
}
ostream & operator<<(ostream &s, const NumExpr &num) {
s << num.number;
return s;
}
I made it a friend function so it can access the private variable
class NumExpr : public Expr {
public:
NumExpr( string v );
string name();
private:
int number;
friend ostream& operator<<(ostream &s, const NumExpr &num);
};
However I'm getting this error
./ast/Expr.cpp: In function ?std::ostream& operator<<(std::ostream&, const NumExpr&)?:
./ast/Expr.cpp:50: error: no match for ?operator<NumExpr::number?
./ast/Expr.cpp:49: note: candidates are: std::ostream& operator<<(std::ostream&, const NumExpr&)
I have searched for this error, people seem to be having the same problems but mine seems to look like the solutions people are giving out. Is there something fundamentally wrong that I'm doing or is there some syntax shenanigans that I'm not aware of?
Thanks for the help!
Okay here it is, little bit of playing around I can reproduce your problem:
The problem is that You forgot to include iostream header file.
Add:
#include<iostream>
and it should just work fine :)
EDIT:
As #James Kanze correctly suggests in comments, it is sufficient to include
#include<istream>
because you don't need everything from the iostream really.
The downside of including iostream inside of istream is little increase in compilation time.
On this page:
http://www.cplusplus.com/forum/beginner/13164/
It says to have the friend function like this:
friend std::ostream& operator<< (std::ostream&, const NumExpr&); <-
so no variable decleration. just
const NumExpr
any help?

c++ error : (private data member) was not declared in this scope

Say I have a class like so:
class Ingredient
{
public:
friend istream& operator>>(istream& in, Ingredient& target);
friend ostream& operator<<(ostream& out, Ingredient& data);
private:
Measure myMeas;
MyString myIng;
};
In this overloaded friend function, I'm trying to set the value of myIng
istream& operator>>(istream& in, Ingredient& target)
{
myIng = MyString("hello");
}
In my mind, this should work because I'm setting the value of a private data member of the class Ingredient in a friend function and the friend function should have access to all the private data members right?
But I get this error: ‘myIng’ was not declared in this scope
Any idea on why this is happening?
Because you need to be be explicit that you are accessing a member of the target parameter, not a local or global variable:
istream& operator>>(istream& in, Ingredient& target)
{
target.myIng = MyString("hello"); // accessing a member of target!
return in; // to allow chaining
}
The above will work exactly because the operator is a friend of Ingredient as you mention. Try removing the friendship and you will see that accessing private members will no longer be possible.
Also, as Joe comments: stream operators should return their stream parameter so that you can chain them.
In that scope, there is nothing called myIng. The error is pretty clear on that. Its Ingredient& target who has a myIng member, so you should write:
target.myIng = MyString("hello");