Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Trouble with overloading << operator via friend

Reply
Thread Tools

Trouble with overloading << operator via friend

 
 
magnus.moraberg@gmail.com
Guest
Posts: n/a
 
      05-14-2009
Hi, I have the following class -

#ifndef CASE_H_
#define CASE_H_

#include <QString>
#include <QStringList>
#include <QRegExp>
#include <QDir>
#include <stdexcept>
#include <iostream>

namespace FS
{

class Case
{
private:
QString name;
unsigned int version;

public:

...

friend std:stream& operator<<(std:stream& outStream, const Case&
case1);
};

}
#endif //CASE_H_

In my cpp file I include this function -

#include "Case.h"

using namespace FS;

....

std:stream& operator<<(std:stream& outStream, const Case& case1)
{
return outStream << case1.name.toStdString() << " v" <<
case1.version.toStdString();
}

However, this gives the error -

Case.h: In function ‘std:stream& operator<<(std:stream&, const
FS::Case&)’:
Case.h:27: error: ‘QString FS::Case::name’ is private
Case.cpp:50: error: within this context
Case.h:28: error: ‘unsigned int FS::Case::version’ is private
Case.cpp:50: error: within this context
Case.cpp:50: error: request for member ‘toStdString’ in ‘case1-
>FS::Case::version’, which is of non-class type ‘const unsigned int’


Does the friend not have access to the private members?

Thanks,

Barry.
 
Reply With Quote
 
 
 
 
magnus.moraberg@gmail.com
Guest
Posts: n/a
 
      05-14-2009
On May 14, 1:37*pm, (E-Mail Removed) wrote:
> Hi, I have the following class -
>
> #ifndef CASE_H_
> #define CASE_H_
>
> #include <QString>
> #include <QStringList>
> #include <QRegExp>
> #include <QDir>
> #include <stdexcept>
> #include <iostream>
>
> namespace FS
> {
>
> class Case
> {
> private:
> * * * * QString name;
> * * * * unsigned int version;
>
> public:
>
> * * * * ...
>
> * * * * friend std:stream& operator<<(std:stream& outStream, const Case&
> case1);
>
> };
> }
>
> #endif //CASE_H_
>
> In my cpp file I include this function -
>
> #include "Case.h"
>
> using namespace FS;
>
> ...
>
> std:stream& operator<<(std:stream& outStream, const Case& case1)
> {
> * * * * return outStream << case1.name.toStdString() << " v" <<
> case1.version.toStdString();
>
> }
>
> However, this gives the error -
>
> Case.h: In function ‘std:stream& operator<<(std:stream&, const
> FS::Case&)’:
> Case.h:27: error: ‘QString FS::Case::name’ is private
> Case.cpp:50: error: within this context
> Case.h:28: error: ‘unsigned int FS::Case::version’ is private
> Case.cpp:50: error: within this context
> Case.cpp:50: error: request for member ‘toStdString’ in ‘case1-
>
> >FS::Case::version’, which is of non-class type ‘const unsigned int’

>
> Does the friend not have access to the private members?
>
> Thanks,
>
> Barry.


Hi,

I tried -

std:stream& FS:perator<<(std:stream& outStream, const Case&
case1)
{
return outStream << case1.name.toStdString() << " v" <<
case1.version;
}

but this gave me -

Case.cpp:49: error: ‘std:stream& FS:perator<<(std:stream&, const
FS::Case&)’ should have been declared inside ‘FS’


Then I tried this -

#include "Case.h"

using namespace FS;

....

namespace FS
{
std:stream& FS:perator<<(std:stream& outStream, const Case&
case1fg
{
return outStream << case1.name.toStdString() << " v" <<
case1.version;
}
}

and now it works. Not sure I fully understand though. Pity book
examples don't include namespaces in all examples...
 
Reply With Quote
 
 
 
 
Neelesh
Guest
Posts: n/a
 
      05-14-2009
On May 14, 4:50*pm, (E-Mail Removed) wrote:
> On May 14, 1:37*pm, (E-Mail Removed) wrote:
>
>
>
>
>
> > Hi, I have the following class -

>
> > #ifndef CASE_H_
> > #define CASE_H_

>
> > #include <QString>
> > #include <QStringList>
> > #include <QRegExp>
> > #include <QDir>
> > #include <stdexcept>
> > #include <iostream>

>
> > namespace FS
> > {

>
> > class Case
> > {
> > private:
> > * * * * QString name;
> > * * * * unsigned int version;

>
> > public:

>
> > * * * * ...

>
> > * * * * friend std:stream& operator<<(std:stream& outStream, const Case&
> > case1);

>
> > };
> > }

>
> > #endif //CASE_H_

>
> > In my cpp file I include this function -

>
> > #include "Case.h"

>
> > using namespace FS;

>
> > ...

>
> > std:stream& operator<<(std:stream& outStream, const Case& case1)
> > {
> > * * * * return outStream << case1.name.toStdString() << " v" <<
> > case1.version.toStdString();

>
> > }

>
> > However, this gives the error -

>
> > Case.h: In function ‘std:stream& operator<<(std:stream&, const
> > FS::Case&)’:
> > Case.h:27: error: ‘QString FS::Case::name’ is private
> > Case.cpp:50: error: within this context
> > Case.h:28: error: ‘unsigned int FS::Case::version’ is private
> > Case.cpp:50: error: within this context
> > Case.cpp:50: error: request for member ‘toStdString’ in ‘case1-

>
> > >FS::Case::version’, which is of non-class type ‘const unsigned int’

>
> > Does the friend not have access to the private members?

>


It has, but operator<< is defined inside namespace FS and hence it
must be defined by explicitly qualifying with FS:: or inside the
namespace FS. Otherwise the compiler will think that you are defining
a different operator<< in the global namespace.

>
> I tried -
>
> std:stream& FS:perator<<(std:stream& outStream, const Case&
> case1)
> {
> * * * * return outStream << case1.name.toStdString() << " v" <<
> case1.version;
>
> }
>
> but this gave me -
>
> Case.cpp:49: error: ‘std:stream& FS:perator<<(std:stream&, const
> FS::Case&)’ should have been declared inside ‘FS’
>


Well, the C++ standard seems to say that explicit qualification as
done above is fine:
7.3.1.2/2:

Members of a named namespace can also be defined outside that
namespace by explicit qualification
(3.4.3.2) of the name being defined, provided that the entity being
defined was already declared in the namespace and the definition
appears after the point of declaration in a namespace that encloses
the declaration’s namespace.

Also, 7.3.1.2/3:
If a friend declaration in a nonlocal class first declares a class or
function83) the friend class or function is a member of the innermost
enclosing namespace

This means that operator<< belongs to namespace FS and it can be
defined outside namespace FS by explicitly qualifying the name, like
FS:perator<<

Which compiler did you try on? g++ 3.4 seems to compile this code
correctly, and I could'nt try on latest version. Comeau online,
however gives error. I'm not sure why.

> Then I tried this -
>
> #include "Case.h"
>
> using namespace FS;
>
> ...
>
> namespace FS
> {
> std:stream& FS:perator<<(std:stream& outStream, const Case&
> case1fg
> {
> * * * * return outStream << case1.name.toStdString() << " v" <<
> case1.version;
>
> }
> }
>
> and now it works.


Yes it will, since we are explicitly defining operator<< inside
namespace FS. Further, there is no need of explicitly qualifying
operator<< now, you can simply say

namespace FS
{
std:stream& operator<<(std:stream& outStream, const Case& case1)
}




 
Reply With Quote
 
Neelesh
Guest
Posts: n/a
 
      05-14-2009
On May 14, 10:40*pm, Neelesh <(E-Mail Removed)> wrote:
> On May 14, 4:50*pm, (E-Mail Removed) wrote:
>
>
>
>
>
> > On May 14, 1:37*pm, (E-Mail Removed) wrote:

>
> > > Hi, I have the following class -

>
> > > #ifndef CASE_H_
> > > #define CASE_H_

>
> > > #include <QString>
> > > #include <QStringList>
> > > #include <QRegExp>
> > > #include <QDir>
> > > #include <stdexcept>
> > > #include <iostream>

>
> > > namespace FS
> > > {

>
> > > class Case
> > > {
> > > private:
> > > * * * * QString name;
> > > * * * * unsigned int version;

>
> > > public:

>
> > > * * * * ...

>
> > > * * * * friend std:stream& operator<<(std:stream& outStream, const Case&
> > > case1);

>
> > > };
> > > }

>
> > > #endif //CASE_H_

>
> > > In my cpp file I include this function -

>
> > > #include "Case.h"

>
> > > using namespace FS;

>
> > > ...

>
> > > std:stream& operator<<(std:stream& outStream, const Case& case1)
> > > {
> > > * * * * return outStream << case1.name.toStdString() << " v" <<
> > > case1.version.toStdString();

>
> > > }

>
> > > However, this gives the error -

>
> > > Case.h: In function ‘std:stream& operator<<(std:stream&, const
> > > FS::Case&)’:
> > > Case.h:27: error: ‘QString FS::Case::name’ is private
> > > Case.cpp:50: error: within this context
> > > Case.h:28: error: ‘unsigned int FS::Case::version’ is private
> > > Case.cpp:50: error: within this context
> > > Case.cpp:50: error: request for member ‘toStdString’ in ‘case1-

>
> > > >FS::Case::version’, which is of non-class type ‘const unsigned int’

>
> > > Does the friend not have access to the private members?

>
> It has, but operator<< is defined inside namespace FS and hence it
> must be defined by explicitly qualifying with FS:: or inside the
> namespace FS. Otherwise the compiler will think that you are defining
> a different operator<< in the global namespace.
>
>
>
>
>
> > I tried -

>
> > std:stream& FS:perator<<(std:stream& outStream, const Case&
> > case1)
> > {
> > * * * * return outStream << case1.name.toStdString() << " v" <<
> > case1.version;

>
> > }

>
> > but this gave me -

>
> > Case.cpp:49: error: ‘std:stream& FS:perator<<(std:stream&, const
> > FS::Case&)’ should have been declared inside ‘FS’

>
> Well, the C++ standard seems to say that explicit qualification as
> done above is fine:
> 7.3.1.2/2:
>
> Members of a named namespace can also be defined outside that
> namespace by explicit qualification
> (3.4.3.2) of the name being defined, provided that the entity being
> defined was already declared in the namespace and the definition
> appears after the point of declaration in a namespace that encloses
> the declaration’s namespace.
>
> Also, 7.3.1.2/3:
> If a friend declaration in a nonlocal class first declares a class or
> function83) the friend class or function is a member of the innermost
> enclosing namespace
>
> This means that operator<< belongs to namespace FS and it can be
> defined outside namespace FS by explicitly qualifying the name, like
> FS:perator<<
>
> Which compiler did you try on? g++ 3.4 seems to compile this code
> correctly, and I could'nt try on latest version. Comeau online,
> however gives error. I'm not sure why.


hmm, g++ 4.3 seems to give the error that you pointed out.

7.3.1.2/3 says:

If a friend declaration in a nonlocal class first declares a class or
function83) the friend class or function is a member of the innermost
enclosing namespace. The name of the friend is not found by simple
name lookup until a matching declaration is provided in that namespace
scope (either before or after the class declaration granting
friendship).

The second part of above paragraph indicates that the name of the
friend would not be found until a matching declaration is provided
into the namespace scope. This explains why the above error comes: You
cannot use FS:perator<< until operator<< is declared inside
namespace FS.

Observe that the above rule doesn't need "definition" to be inside
namespace FS. Hence the following would compile well:

namespace FS
{
std:stream& operator<<(std:stream& outStream, const Case&
case1) ;
}
std:stream& FS:perator<<(std:stream& outStream, const Case&
case1)
{
* * * * return outStream << case1.name.toStdString() << " v" <<
case1.version;
}

Once we declare the name inside namespace FS, we can define it using
FS:perator<< in the global namespacea also.

Hope this helps.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-15-2009
On May 14, 1:37 pm, (E-Mail Removed) wrote:
> Hi, I have the following class -


> #ifndef CASE_H_
> #define CASE_H_


> #include <QString>
> #include <QStringList>
> #include <QRegExp>
> #include <QDir>
> #include <stdexcept>
> #include <iostream>


> namespace FS
> {


> class Case
> {
> private:
> QString name;
> unsigned int version;


> public:


> ...


> friend std:stream& operator<<(std:stream& outStream, const Case&
> case1);


The friend function is thus ::FS:perator<<(...).

> };
> }


> #endif //CASE_H_


> In my cpp file I include this function -


> #include "Case.h"


> using namespace FS;


> ...


> std:stream& operator<<(std:stream& outStream, const Case& case1)


And here you define :perator<<(...). A totally unrelated
function. Either put this definition in namespace FS, or define
it:
std:stream& FS:perator<<( ... ) ...

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-15-2009
On May 14, 1:50 pm, (E-Mail Removed) wrote:
> On May 14, 1:37 pm, (E-Mail Removed) wrote:
> I tried -


> std:stream& FS:perator<<(std:stream& outStream, const Case&
> case1)
> {
> return outStream << case1.name.toStdString() << " v" <<
> case1.version;
> }


> but this gave me -


> Case.cpp:49: error: ¿std:stream& FS:perator<<(std:stream&, const
> FS::Case&)¿ should have been declared inside ¿FS¿


A frequent problem. The friend declaration declared a function
::FS:perator<<, but it declared it in the class scope, so it
is only visible in the class (or through ADL). The rules for
defining a function using the namespace qualifiers, as you do
here, require a visible declaration of the function.

> Then I tried this -


> #include "Case.h"


> using namespace FS;


> ...


> namespace FS
> {
> std:stream& FS:perator<<(std:stream& outStream, const Case&
> case1fg


You don't need the FS;;, here. You are in namespace FS, just as
you were in the class definition. (As far as I can tell, it's
not even legal. The standard seems to clearly say that if the
declarator-id is qualified, then it must refer to a previously
declared member of the namespace or class.)

> {
> return outStream << case1.name.toStdString() << " v" <<
> case1.version;
> }
> }


> and now it works. Not sure I fully understand though.


The various rules for name lookup are rather complicated, and
not particularly intuitive. In this case, the definition also
declares the function in FS (provided you drop the FS:: in it).

In general, the simplest rule is to simply ensure that
everything in namespace NS is defined and declared in that
namespace, and to not worry about qualified names (except for
classes) in declarations and definitions.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-15-2009
On May 14, 7:40 pm, Neelesh <(E-Mail Removed)> wrote:
> On May 14, 4:50 pm, (E-Mail Removed) wrote:
> > On May 14, 1:37 pm, (E-Mail Removed) wrote:


> > I tried -


> > std:stream& FS:perator<<(std:stream& outStream, const Case&
> > case1)
> > {
> > return outStream << case1.name.toStdString() << " v" <<
> > case1.version;
> > }


> > but this gave me -


> > Case.cpp:49: error: ¿std:stream& FS:perator<<(std:stream&, const
> > FS::Case&)¿ should have been declared inside ¿FS¿


> Well, the C++ standard seems to say that explicit
> qualification as done above is fine:
> 7.3.1.2/2:


> Members of a named namespace can also be defined outside that
> namespace by explicit qualification
> (3.4.3.2) of the name being defined, provided that the entity being
> defined was already declared in the namespace and the definition
> appears after the point of declaration in a namespace that encloses
> the declaration¿s namespace.


The problem is that there is no visible declaration of the
entity in question (::FS:perator<<). The friend declaration
does NOT inject the name into the surrounding namespace.

> Also, 7.3.1.2/3:
> If a friend declaration in a nonlocal class first declares a class or
> function83) the friend class or function is a member of the innermost
> enclosing namespace


> This means that operator<< belongs to namespace FS and it can be
> defined outside namespace FS by explicitly qualifying the name, like
> FS:perator<<


The issue isn't simple, mainly (I think) for want of a good,
well established vocabulary to explain it. The friend
declaration declares a function in the immediately surrounding
namespace, but the declaration itself is in class scope, and is
treated exactly as if it were in class scope. In his code,
there is no declaration of the operator<< in scope when he tries
to define it, so his declaration is illegal.

The simplest solution, in his case, is simply to open the
namespace, and define the function (using an unqualified name)
there. More generally, he might want to provide a declaration
in namespace scope in the header, e.g.:

namespace FS {
class Case ;
std:stream& operator<<( std:stream&, Case const& ) ;

class Case
{
// As in his original code...
} ;
}

If he does this, then he should be able to define

std:stream& FS:perator<<(
std:stream& dest,
Case const& object )
{
// ...
}

without any problems.

(Another alternative would be to define the operator<< inline in
the friend declaration. This avoids the problem entirely.)

> Which compiler did you try on? g++ 3.4 seems to compile this code
> correctly, and I could'nt try on latest version. Comeau online,
> however gives error. I'm not sure why.


In pre-standard days, a friend declaration injected the declared
name into file scope (there were no namespaces then). This
caused some problem, I forget what. (I've had it explained to
me three or four times; I just keep forgetting.) And the needed
functionality was subsumed by ADL, at least in the cases deemed
necessary. So the committee dropped the injection. Many older
compilers, however, still implement it; I think you'll find that
g++ changed with 4.0 (or something like that). (Of the
compilers I have handy, g++ 4.3.3 rejects it, but g++ 3.4.0, Sun
CC 5.8, and the VC++ from Visual Studios 8 all accept it.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
user defined conversion operator or operator overloading? hurcan solter C++ 3 08-29-2007 07:39 PM
Why is overloading operator. (member operator) forbidden? dascandy@gmail.com C++ 11 05-16-2007 07:54 PM
Overloading operator<< as a friend to a template class CrimzonRJ@gmail.com C++ 4 09-30-2006 01:27 PM
Operator overloading on "default" operator John Smith C++ 2 10-06-2004 10:22 AM
overloading operator<< as global friend funcion Robert Wierschke C++ 3 08-03-2004 04:59 AM



Advertisments