C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Private Member Access failed through Friend function

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Abhi Win
Guest





PostPosted: Sat Apr 28, 2007 8:29 pm    Post subject: Private Member Access failed through Friend function Reply with quote



Hi All,

I am facing a strange problem in VC6 compiler. It gives error to
access a private member from a friend function.
Also, its showing ambiguity in use of '<<' operator.

Here is the complete code :

<code>
#include <iostream>
using namespace std;

class Data
{
private:
int i;

public:
Data() : i(0) {}
Data(int d) : i(d) {}

void print(ostream &out)
{
out.width(3);
out << i;
}

void print()
{
print( cout );
}

friend ostream& operator << (ostream &out, Data &d);
};

ostream& operator << (ostream &out, Data &d)
{
out<<d.i;
//d.print( out );

return out;
}

int main()
{
Data d;
cout << d;

return 0;
}
</code>

Here are the error messages :

error C2248: 'i' : cannot access private member declared in class
'Data'
see declaration of 'i'
'operator <<' is ambiguous


Please tell me why this is not working or where I am going wrong.

Thanks & Regards


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Salt_Peter
Guest





PostPosted: Sun Apr 29, 2007 5:29 am    Post subject: Re: Private Member Access failed through Friend function Reply with quote



On Apr 28, 4:29 pm, Abhi Win <abhi....@gmail.com> wrote:
Quote:
Hi All,

I am facing a strange problem in VC6 compiler. It gives error to
access a private member from a friend function.
Also, its showing ambiguity in use of '<<' operator.

Here is the complete code :

code
#include <iostream

#include <ostream> // required to overload stream op<<

Quote:
using namespace std;

class Data
{
private:
int i;

public:
Data() : i(0) {}
Data(int d) : i(d) {}

void print(ostream &out)
{
out.width(3);
out << i;
}

void print()
{
print( cout );
}

friend ostream& operator << (ostream &out, Data &d);

};

ostream& operator << (ostream &out, Data &d)

std::ostream& operator<< (std::ostream& out, const Data& d)

Quote:
{
out<<d.i;
//d.print( out );

return out;

}

int main()
{
Data d;
cout << d;

return 0;}

/code

Here are the error messages :

error C2248: 'i' : cannot access private member declared in class
'Data'
see declaration of 'i'
'operator <<' is ambiguous

Please tell me why this is not working or where I am going wrong.

Thanks & Regards




--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Abhishek Padmanabh
Guest





PostPosted: Sun Apr 29, 2007 5:44 pm    Post subject: Re: Private Member Access failed through Friend function Reply with quote



On Apr 29, 10:29 am, Salt_Peter <pj_h...@yahoo.com> wrote:
Quote:
On Apr 28, 4:29 pm, Abhi Win <abhi....@gmail.com> wrote:

#include <ostream> // required to overload stream op


That isn't enough on VC6, he needs to add this on the top of his class
declaration:

class Data;
ostream& operator << (ostream &out, Data &d);


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Richard Smith
Guest





PostPosted: Sun Apr 29, 2007 6:09 pm    Post subject: Re: Private Member Access failed through Friend function Reply with quote

Salt_Peter wrote:
Quote:
On Apr 28, 4:29 pm, Abhi Win <abhi....@gmail.com> wrote:

I am facing a strange problem in VC6 compiler. It gives error to
access a private member from a friend function.
Also, its showing ambiguity in use of '<<' operator.

The code is correct -- it is the compiler that is at fault. (MSVC 6
really is an ancient compiler and its C++ implementation is full of bugs
-- unsurpisingly given it was realeased at about the same time that the
C++ standard was published. Have you considered upgrading? I gather
the 'Express' version of MSVC 8 can be downloaded for free.)

Quote:
Here is the complete code :

code
#include <iostream


#include <ostream> // required to overload stream op

You are correct to say that <ostream> is required, but it is *not*
required to overload operator<<. The reason that it is required is that
there is no requirement for <iostream> to define the std::ostream
typedef; there is also no requirement for it to define the overload of
operator<< that acts streams an int into an ostream.

Quote:
using namespace std;

class Data
{
private:
int i;

public:
Data() : i(0) {}
Data(int d) : i(d) {}

void print(ostream &out)
{
out.width(3);
out << i;
}

void print()
{
print( cout );
}

friend ostream& operator << (ostream &out, Data &d);

I strongly suspect that this is what is confusing the compiler (though
as I don't have access to that particular version of the compiler, I
cannot be sure). Assuming I've identified the problem correctly, there
are two possible solutions:

1. Forward declare the function before the class definition. This
means adding the following two lines before "class Data { ...":

class Data;
ostream& operator<<( ostream&, Data& );

2. Define the operator in the class body: instead of the friend
declaration that you have, put a complete definition:

friend ostream& operator<<( ostream& os, Data& d ) {
return os << d.i;
}

and remove the definition from the end of the class.


By the way, you may hear people saying that friends are always bad and
that you should always implement operator<< in terms of a public print()
function. Don't believe them! Yes, it is true that friend functions
can be overused and can result in broken encapsulation, but that's not
the same as saying that all friend functions are signs of bad design.
IMHO a friend operator<< is better better than introducing an
unnecessary print() function. That said, if you can implement
operator<< through the public interface of the class *without* injecting
an additional print() function, that's much better still!

Quote:
};

ostream& operator << (ostream &out, Data &d)


std::ostream& operator<< (std::ostream& out, const Data& d)

Irrelevant.

There was a using directive at the start of the file (using namespace
std;) so std:: qualifications are not needed. You may not like this
usage, and when used in a header (which this isn't) it can cause
problems, but it's use in a source file can improve readability.

The missing const is certainly unusual and is almost certaintly a
mistake, but it is also irrelevant to problem the OP is experiencing.
(Incidentally, if you correct the const here, you should also const
qualify the two print member functions.)

Quote:
{
out<<d.i;
//d.print( out );

return out;

}

int main()
{
Data d;
cout << d;

return 0;}

/code

Here are the error messages :

error C2248: 'i' : cannot access private member declared in class
'Data'
see declaration of 'i'
'operator <<' is ambiguous

Please tell me why this is not working or where I am going wrong.

The problem is that the compiler is failing to realise that the function
you've declared as a friend is the same one as the function you've
defined after the body of the class.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Craig Scott
Guest





PostPosted: Mon Apr 30, 2007 9:10 am    Post subject: Re: Private Member Access failed through Friend function Reply with quote

Quote:
You are correct to say that <ostream> is required, but it is *not*
required to overload operator<<. The reason that it is required is that
there is no requirement for <iostream> to define the std::ostream
typedef;

<iostream> defines cout, cerr and clog, which according to 27.3.1 of
the standard are all defined in terms of ostream. Therefore, one can
conclude that including <iostream> must guarantee that std::ostream
will be defined. That said, if <ostream> is all you need, then better
to use it instead of <iostream>.

--
Computational Fluid Dynamics, CSIRO (CMIS)
Melbourne, Australia


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Seungbeom Kim
Guest





PostPosted: Mon Apr 30, 2007 9:10 am    Post subject: Re: Private Member Access failed through Friend function Reply with quote

Richard Smith wrote:
Quote:

By the way, you may hear people saying that friends are always bad and
that you should always implement operator<< in terms of a public print()
function. Don't believe them! Yes, it is true that friend functions
can be overused and can result in broken encapsulation, but that's not
the same as saying that all friend functions are signs of bad design.
IMHO a friend operator<< is better better than introducing an
unnecessary print() function. That said, if you can implement
operator<< through the public interface of the class *without* injecting
an additional print() function, that's much better still!

I agree, but I'd also like to point out a situation where defining a
separate print() function would be useful: polymorphic classes. Because
calls to operator<< cannot be dispatched virtually depending on the
right-hand side operand, defining virtual print() functions and calling
that of the base class in operator<<(std::ostream&, const Base&) is
almost "the" right answer.

class Base
{
public:
virtual void print(std::ostream&) /* = 0 as necessary */;
};

std::ostream& operator<<(std::ostream& os, const Base& b)
{ b.print(os); return os; }

class Derived1 : public Base
{
public:
virtual void print(std::ostream&);
};

class Derived2 : public Base
{
public:
virtual void print(std::ostream&);
};

--
Seungbeom Kim

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Richard Smith
Guest





PostPosted: Mon Apr 30, 2007 5:58 pm    Post subject: Re: Private Member Access failed through Friend function Reply with quote

Craig Scott wrote:
Quote:
You are correct to say that <ostream> is required, but it is *not*
required to overload operator<<. The reason that it is required is that
there is no requirement for <iostream> to define the std::ostream
typedef;


iostream> defines cout, cerr and clog, which according to 27.3.1 of
the standard are all defined in terms of ostream. Therefore, one can
conclude that including <iostream> must guarantee that std::ostream
will be defined
Not at all. First there's no reason why cout should be declaring using

the ostream typedef: it could be defined as basic_ostream<char>.
Second, it is a declaration not a definition, and as such doesn't need
its type to be complete. So it's entirely possible that <iostream>
would just include <iosfwd> (or equivalent), std::ostream wouldn't be
declared.

The main reason why implementation don't do this is because
implementations never have and it would mean that a lot of "hello world"
programs in introductory books on C++ would suddenly stop compiling.
That aside, it would seem a good strategy: I find that in real world
programs (as opposed to short 'toy' examples), those translation units
in which I use cout (et al.) rarely require basic_ostream to be a
complete type. (Generally, they're high level translation units passing
an ostream down to some lower-level module.)

--
Richard Smith

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Marcus Kwok
Guest





PostPosted: Mon Apr 30, 2007 9:36 pm    Post subject: Re: Private Member Access failed through Friend function Reply with quote

Abhi Win <abhi.win (AT) gmail (DOT) com> wrote:
Quote:
I am facing a strange problem in VC6 compiler. It gives error to
access a private member from a friend function.
Also, its showing ambiguity in use of '<<' operator.

Here is the complete code :

[code snipped]

Here are the error messages :

error C2248: 'i' : cannot access private member declared in class
'Data'
see declaration of 'i'
'operator <<' is ambiguous


Please tell me why this is not working or where I am going wrong.

The code looks OK to me, and it compiles fine with VC 7.1 and Comeau
Online.

Also, VC6 is not known to be very standards-compliant since it predates
the 1998 Standard. More recent versions are much better in this
respect, and you can get VS 2005 Express for free from Microsoft.

--
Marcus Kwok
Replace 'invalid' with 'net' to reply

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Cumhur Guzel
Guest





PostPosted: Wed May 02, 2007 9:10 am    Post subject: Re: Private Member Access failed through Friend function Reply with quote

{ Quoted banner & signature removed. Note: most Usenet client programs
will do that automatically for you (hint hint). -mod }

On Apr 30, 7:12 pm, Seungbeom Kim <musip...@bawi.org> wrote:
Quote:
Richard Smith wrote:

By the way, you may hear people saying that friends are always bad and
that you should always implement operator<< in terms of a public print()
function. Don't believe them! Yes, it is true that friend functions
can be overused and can result in broken encapsulation, but that's not
the same as saying that all friend functions are signs of bad design.
IMHO a friend operator<< is better better than introducing an
unnecessary print() function. That said, if you can implement
operator<< through the public interface of the class *without* injecting
an additional print() function, that's much better still!

I agree, but I'd also like to point out a situation where defining a
separate print() function would be useful: polymorphic classes. Because
calls to operator<< cannot be dispatched virtually depending on the
right-hand side operand, defining virtual print() functions and calling
that of the base class in operator<<(std::ostream&, const Base&) is
almost "the" right answer.

class Base
{
public:
virtual void print(std::ostream&) /* = 0 as necessary */;

};

std::ostream& operator<<(std::ostream& os, const Base& b)
{ b.print(os); return os; }

class Derived1 : public Base
{
public:
virtual void print(std::ostream&);

};

class Derived2 : public Base
{
public:
virtual void print(std::ostream&);

};

Hi,

I think you could get better encapsulation plus flexibility by using
the template method pattern with NVI,
as given below. As far as I remember, something similar to given below
is suggested in Meyer's Effective C++
or More Effective C++;

Regards

namespace X
{

class Base
{
public:
void print(std::ostream& os)
{
myprint(os);
};
private:
virtual void myprint(std::ostream&)=0;
};

class D1: Base
{
private:
virtual void myprint(std::ostream&) {};
};

class D2: Base
{
private:
virtual void myprint(std::ostream&) {};
};

std::ostream& operator<<(std::ostream& os, Base& b)
{ b.print(os); return os; };


void f()
{
std::cout << new D2;
std::cout << new D1;
}

};

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Salt_Peter
Guest





PostPosted: Wed May 02, 2007 6:05 pm    Post subject: Re: Private Member Access failed through Friend function Reply with quote

On Apr 29, 1:44 pm, Abhishek Padmanabh <abhishek.padman...@gmail.com>
wrote:
Quote:
On Apr 29, 10:29 am, Salt_Peter <pj_h...@yahoo.com> wrote:

On Apr 28, 4:29 pm, Abhi Win <abhi....@gmail.com> wrote:

#include <ostream> // required to overload stream op

That isn't enough on VC6, he needs to add this on the top of his class
declaration:

class Data;
ostream& operator << (ostream &out, Data &d);

- constant Data - !!!!!!!!!!!!!!!!
ostream& operator<<(ostream& out, const Data& d);

Nobody cares what VC6 might or might not need. If you wish to discuss
particular problems with this particular compiler, feel free to do so
in the appropriate forum for such a topic. Any reason why you aren't
using a freely available VC8?


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Seungbeom Kim
Guest





PostPosted: Wed May 02, 2007 10:06 pm    Post subject: Re: Private Member Access failed through Friend function Reply with quote

Cumhur Guzel wrote:
Quote:
{ Quoted banner & signature removed. Note: most Usenet client programs
will do that automatically for you (hint hint). -mod }

On Apr 30, 7:12 pm, Seungbeom Kim <musip...@bawi.org> wrote:
I agree, but I'd also like to point out a situation where defining a
separate print() function would be useful: polymorphic classes. Because
calls to operator<< cannot be dispatched virtually depending on the
right-hand side operand, defining virtual print() functions and calling
that of the base class in operator<<(std::ostream&, const Base&) is
almost "the" right answer.

I think you could get better encapsulation plus flexibility by using
the template method pattern with NVI,
as given below. As far as I remember, something similar to given below
is suggested in Meyer's Effective C++
or More Effective C++;

Can you elaborate on "better encapsulation plus flexibility" we can get
here?

Quote:
class Base
{
public:
void print(std::ostream& os)
{
myprint(os);
};
private:
virtual void myprint(std::ostream&)=0;
};

It's basically the same idea; the non-virtual interface pattern you
showed is something to add on top of the "virtual member + non-member
operator<<" pattern, not a replacement of it. The basic idea that the
non-member operator<< calls a virtual member remains the same.

Furthermore, the purpose of the NVI pattern is to enforce some pre-
and/or post-condition to the virtual functions. Since there's no
additional conditions to enforce in your print function (and it's not
very likely that you'll have any in the future), there's little point in
having a separate non-virtual member that calls the virtual member.

Still, we could consider my example as a variation of the NVI pattern,
for a different purpose: to provide a different syntax (os << obj
instead of obj.print(os)). The non-member operator<< here serves as the
non-virtual interface in the NVI pattern. (For a complete analogy, you
could make the virtual member private and make the non-member a friend.)

--
Seungbeom Kim

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Richard Smith
Guest





PostPosted: Wed May 02, 2007 10:09 pm    Post subject: Re: Private Member Access failed through Friend function Reply with quote

On May 2, 10:42 am, Cumhur Guzel <guzelcum...@gmail.com> wrote:
Quote:
I think you could get better encapsulation plus flexibility by using
the template method pattern with NVI,

namespace X {
class Base {
public:
void print(std::ostream& os) {
myprint(os);
}
private:
virtual void myprint(std::ostream&)=0;
};

class D1: Base {
private:
virtual void myprint(std::ostream&) {};
};

class D2: Base {
private:
virtual void myprint(std::ostream&) {};
};

std::ostream& operator<<(std::ostream& os, Base& b) {
b.print(os); return os;
}

(I assume the non-cost Base parameter and the private inheritance are
typos.)

And this is back to an example where I think a friend function is
preferable to a public print() function:

class Base {
private:
virtual void do_print(std::ostream&) = 0;

friend ostream& operator<<( ostream& os, Base const& b ) {
b.do_print(os); return os;
}
};

Why introduce the redundant print() function when you can do it
directly with the more idiomatic operator<< simply by making it a
friend?

--
Richard Smith


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Craig Scott
Guest





PostPosted: Thu May 03, 2007 2:46 am    Post subject: Re: Private Member Access failed through Friend function Reply with quote

On May 1, 3:58 am, Richard Smith <rich...@ex-parrot.com> wrote:
Quote:
Craig Scott wrote:
You are correct to say that <ostream> is required, but it is *not*
required to overload operator<<. The reason that it is required is that
there is no requirement for <iostream> to define the std::ostream
typedef;

iostream> defines cout, cerr and clog, which according to 27.3.1 of
the standard are all defined in terms of ostream. Therefore, one can
conclude that including <iostream> must guarantee that std::ostream
will be defined

Not at all. First there's no reason why cout should be declaring using
the ostream typedef: it could be defined as basic_ostream<char>.
Second, it is a declaration not a definition, and as such doesn't need
its type to be complete. So it's entirely possible that <iostream
would just include <iosfwd> (or equivalent), std::ostream wouldn't be
declared.

Well, my version of the standard says this for 27.3:

namespace std {
extern istream cin;
extern ostream cout;
extern ostream cerr;
extern ostream clog;
// Wide streams omitted....
}

Note that these are not *references* to ostream, but actual ostream
objects, so ostream must be fully defined. Also note that the standard
defines cout etc. in terms of ostream, not basic_ostream<char>, so
although compilers *could* define them using basic_ostream, they are
*required* by the standard to define them as above, or at least
equivalently. Here, equivalently also means that ostream must be
defined.

Quote:
The main reason why implementation don't do this is because
implementations never have and it would mean that a lot of "hello world"
programs in introductory books on C++ would suddenly stop compiling.
That aside, it would seem a good strategy: I find that in real world
programs (as opposed to short 'toy' examples), those translation units
in which I use cout (et al.) rarely require basic_ostream to be a
complete type. (Generally, they're high level translation units passing
an ostream down to some lower-level module.)

Passing an ostream by reference doesn't require its definition (ie
including <iosfwd> is enough). Once you try to actually use the
ostream for something other than taking its address, you need at least
<ostream>. Just because you didn't explicitly include it doesn't mean
that one of the other headers you included doesn't include <ostream>
itself somewhere. I think you already know this though - I'm just
mentioning it here for new people who might be reading this thread.

--
Computational Fluid Dynamics, CSIRO (CMIS)
Melbourne, Australia


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Craig Scott
Guest





PostPosted: Thu May 03, 2007 11:50 pm    Post subject: Re: Private Member Access failed through Friend function Reply with quote

Quote:
iostream> defines cout, cerr and clog, which according to 27.3.1 of
the standard are all defined in terms of ostream. Therefore, one can
conclude that including <iostream> must guarantee that std::ostream
will be defined

Not at all. First there's no reason why cout should be declaring using
the ostream typedef: it could be defined as basic_ostream<char>.
Second, it is a declaration not a definition, and as such doesn't need
its type to be complete. So it's entirely possible that <iostream
would just include <iosfwd> (or equivalent), std::ostream wouldn't be
declared.

Well, my version of the standard says this for 27.3:

namespace std {
extern istream cin;
extern ostream cout;
extern ostream cerr;
extern ostream clog;
// Wide streams omitted....

}

Note that these are not *references* to ostream, but actual ostream
objects, so ostream must be fully defined.

No, you are wrong. This is not the case because these are only
declarations, not definitions, of objects. A declaration that is not
also a definition does *not* require a complete type.

For chapter and verse, see:

[3.1/2] "A declaration is a definition unless it declares a function
without specifying the function's body (8.4), it contains the extern
specifier (7.1.1) or a linkage-specification24) (7.5) and neither an
initializer nor a function-body, it declares a static data member in a
class declaration (9.4), it is a class name declaration (9.1), or it
is a typedef declaration (7.1.3), a using-declaration (7.3.3), or a
using-directive (7.3.4)."

-- i.e. "extern ostream cout;" is a declaration but not a definition.

[3.1/6] "A program is ill-formed if the definition of any object
gives the object an incomplete type (3.9)."

-- note this does not make a progam ill-formed if a declaration uses
an incomplete type.

And most importantly, [3.2/4], which gives a complete list of contexts
in which a type is required to be complete; one of these (the first
one) is when an object is defined, but the declaration of an object is
not listed.

Indeed, thankyou for the correction. When I was hitting the send
button, those extern's on the definitions of cout, etc. were bugging
me. Should have listened to my thoughts and brushed up my
understanding of those first. ;)

Happy to eat humble pie!

--
Computational Fluid Dynamics, CSIRO (CMIS)
Melbourne, Australia


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
 


Powered by phpBB © 2001, 2006 phpBB Group