POV-Ray : Newsgroups : povray.off-topic : C++ question Server Time
28 Jul 2024 20:23:14 EDT (-0400)
  C++ question (Message 6 to 15 of 15)  
<<< Previous 5 Messages Goto Initial 10 Messages
From: Anthony D  Baye
Subject: Re: C++ question
Date: 3 Oct 2013 14:50:01
Message: <web.524dbba81cbd09d0328783aa0@news.povray.org>
I forgot to uncomment the function definition in point3d.cpp before I
uploaded...

and I made a stupid in my comment:  I forgot that friend functions can access
protected members, but not private members, so you were right that it would be
better off as a free function within the namespace, but it still doesn't work
right when I compile uTest.

Regards,
A.D.B.


Post a reply to this message

From: Le Forgeron
Subject: Re: C++ question
Date: 3 Oct 2013 15:20:15
Message: <524dc36f@news.povray.org>
Le 03/10/2013 20:47, Anthony D. Baye nous fit lire :
> I forgot to uncomment the function definition in point3d.cpp before I
> uploaded...
> 
> and I made a stupid in my comment:  I forgot that friend functions can access
> protected members, but not private members, so you were right that it would be
> better off as a free function within the namespace, but it still doesn't work
> right when I compile uTest.

the operator<< must be implemented in geometry namespace, and friend is
not enough to declare a function.

Enjoy.

diff -r 9b234d20a210 -r 1840dc7961c9 geometry.h
--- a/geometry.h        Thu Oct 03 21:18:39 2013 +0200
+++ b/geometry.h        Thu Oct 03 21:17:32 2013 +0200
@@ -28,6 +28,7 @@
     private:
         double coords[3];
     };
+               ostream &operator <<(ostream &, const point3d &);

     // 3D geometric vector class extends point3d through inheritance.
     // Angles are measured in radians.
diff -r 9b234d20a210 -r 1840dc7961c9 point3d.cpp
--- a/point3d.cpp       Thu Oct 03 21:18:39 2013 +0200
+++ b/point3d.cpp       Thu Oct 03 21:17:32 2013 +0200
@@ -62,9 +62,9 @@
 //    return os;
 //}

-//ostream &operator <<(ostream &os, const point3d &P)
-//{
-//    os << "(" << P.coords[X] << ", " << P.coords[Y] << ", " <<
P.coords[Z] << ")" << endl;
+ostream & geometry::operator <<(ostream &os, const point3d &P)
+{
+    os << "(" << P.coords[X] << ", " << P.coords[Y] << ", " <<
P.coords[Z] << ")" << endl;

-//    return os;
-//}
+    return os;
+}


Post a reply to this message

From: Le Forgeron
Subject: Re: C++ question
Date: 3 Oct 2013 15:22:33
Message: <524dc3f9@news.povray.org>
Le 03/10/2013 21:20, Le_Forgeron nous fit lire :
>  I forgot that friend functions can access
>> protected members, but not private members, 

Hummm... friend can access private. There is no reserved intimacy for
friend.


Post a reply to this message

From: Warp
Subject: Re: C++ question
Date: 3 Oct 2013 15:41:58
Message: <524dc886@news.povray.org>
Anthony D. Baye <Sha### [at] spamnomorehotmailcom> wrote:
> I also tried declaring it as a class function:

This works just fine:

//----------------------------------------------------------------------
#include <iostream>

namespace geometry
{
    class A
    {
     public:
        int value() const { return 5; }
    };

    inline std::ostream& operator<<(std::ostream& os, const A& obj)
    {
        os << obj.value();
        return os;
    }
}

int main()
{
    geometry::A a;
    std::cout << a << std::endl;
}
//----------------------------------------------------------------------


-- 
                                                          - Warp


Post a reply to this message

From: Anthony D  Baye
Subject: Re: C++ question
Date: 3 Oct 2013 16:00:01
Message: <web.524dccb71cbd09d0328783aa0@news.povray.org>
Le_Forgeron <jgr### [at] freefr> wrote:
> Le 03/10/2013 21:20, Le_Forgeron nous fit lire :
> >  I forgot that friend functions can access
> >> protected members, but not private members,
>
> Hummm... friend can access private. There is no reserved intimacy for
> friend.

Not according to the test I did about an hour ago.  I declared the function as a
friend in point3d and defined it in point3d.cpp, and got told off by g++ for
attempting to access point3d's private members.

At any rate, defining it as warp mentioned using the inline keyword seems to
work, but according to what I've read, that just gives the compiler a hint that
it can be copied in wherever it's called rather than being called as a function.
 I suppose that it won't affect the size of my program all that much, but if I'd
wanted it done that way, I could write it that way. (of course, I understand
that typing a function call is easier than copying a chunk of code several
times)

Anyway, the program compiles now, I just wish I could find out why it was being
so stubborn with the friend function of a class contained in a namespace.

Thanks for the assist.

Regards,
A.D.B


Post a reply to this message

From: Anthony D  Baye
Subject: Re: C++ question
Date: 3 Oct 2013 17:15:01
Message: <web.524dddcc1cbd09d0328783aa0@news.povray.org>
here's a puzzle:

In order to use this method with the same operator for vector3d, I have to
remove the const qualifier on the vector3d & argument because of the way my
spherical components are computed.

The class gives the user options for how the vector is displayed when passed to
ostream.

There are two formats, COMPONENT and EXPRESSION and two styles, CARTESIAN and
SPHERICAL, so the ways a vector can be displayed are:

1) <X,Y,Z>
2) mag * <sin(phi) * cos(theta), sin(phi) * sin(theta), cos(phi)>
3) X * x + Y * y + Z * z
4) mag * ( sin(phi) * cos(theta) * x + sin(phi) * sin(theta) * y + cos(phi) * z
)

here's the problem:

the public interface for vector3d provides 3 functions for getting mag, phi and
theta but, rather than having those functions calculate the values every time,
which could get expensive, I store the values the first time one is requested.
As if that weren't enough, there are two methods by which the components can
change: 1) by using the [] operator and 2) by using the getIntercept() function
of vector3d, which returns a reference.

To account for changes in the intercept, vector3d keeps a reference copy for
comparison.  each time one of the spherical components is requested, the
reference is compared to the intercept, and if the two are different, the
function calls a private helper recompute_spherical().

all of this, combined, means that the getters for the spherical components
cannot take a const reference, so they can't be used from any function that has
a const qualifier, or used on a const reference.

because the other operators for vector3d work -exclusively- with the intercept
value, this isn't a problem.  The only place where it's a problem is in the
stream operators << and >>.

I could, of course, make a copy of the variable being displayed and work with
that, but it would negate the benefits of lazy computation.

I suppose that I could create a private lookup table common to all vectors by
using a map contained inside an anonymous namespace.  It should only be
accessible from within the file it's contained in, but it would require the
vector3d ctors to handle insertion and deletion of their component values...

and it would risk adding complexity from the map lookup.

thoughts?

Regards,
A.D.B.


Post a reply to this message

From: Warp
Subject: Re: C++ question
Date: 3 Oct 2013 17:55:49
Message: <524de7e5@news.povray.org>
Anthony D. Baye <Sha### [at] spamnomorehotmailcom> wrote:
> At any rate, defining it as warp mentioned using the inline keyword seems to
> work

The inline keyword has nothing to do with why it works. It's there for
a different reason.

The key is that the function has to be on the outer scope, it cannot be
inside the class. What the 'friend' function declaration does is to
simply say that the function in question can read the private members
of the class. You still have to implement the function outside.

If the function doesn't need to read the private members of the class,
then the 'friend' declaration is pretty obsolete and should be avoided
to keep the code cleaner.

>, but according to what I've read, that just gives the compiler a hint that
> it can be copied in wherever it's called rather than being called as a function.

Actually, 'inline' is an instruction for the linker, but that's another
story, unrelated to the problem you were having.

> Anyway, the program compiles now, I just wish I could find out why it was being
> so stubborn with the friend function of a class contained in a namespace.

The 'friend' declaration inside the class is not enough by itself. It's
simply telling that a function with that signature can access the private
section of the class.

-- 
                                                          - Warp


Post a reply to this message

From: Warp
Subject: Re: C++ question
Date: 3 Oct 2013 18:01:18
Message: <524de92e@news.povray.org>
Anthony D. Baye <Sha### [at] spamnomorehotmailcom> wrote:
> all of this, combined, means that the getters for the spherical components
> cannot take a const reference, so they can't be used from any function that has
> a const qualifier, or used on a const reference.

If you are using a kind of "temp values" as an optimization, and
these values do not affect the external behavior of the class,
you can declare those values as 'mutable', which allows modifying
them even from a const method.

(Well, nothing stops you from making them mutable even if they did
affect the external behavior of the class. What I mean is that this
should be done only when it does not, or else the class becomes badly
designed.)

-- 
                                                          - Warp


Post a reply to this message

From: Anthony D  Baye
Subject: Re: C++ question
Date: 3 Oct 2013 20:20:00
Message: <web.524e08a91cbd09d0328783aa0@news.povray.org>
Warp <war### [at] tagpovrayorg> wrote:
> Anthony D. Baye <Sha### [at] spamnomorehotmailcom> wrote:
> > all of this, combined, means that the getters for the spherical components
> > cannot take a const reference, so they can't be used from any function that has
> > a const qualifier, or used on a const reference.
>
> If you are using a kind of "temp values" as an optimization, and
> these values do not affect the external behavior of the class,
> you can declare those values as 'mutable', which allows modifying
> them even from a const method.
>
> (Well, nothing stops you from making them mutable even if they did
> affect the external behavior of the class. What I mean is that this
> should be done only when it does not, or else the class becomes badly
> designed.)
>
> --
>                                                           - Warp

I've never looked at the mutable keyword...  Thanks for the tip.

Regards,
A.D.B.


Post a reply to this message

From: Le Forgeron
Subject: Re: C++ question
Date: 4 Oct 2013 03:30:25
Message: <524e6e91@news.povray.org>
Le 03/10/2013 21:59, Anthony D. Baye a écrit :
> Le_Forgeron <jgr### [at] freefr> wrote:
>> > Le 03/10/2013 21:20, Le_Forgeron nous fit lire :
>>> > >  I forgot that friend functions can access
>>>> > >> protected members, but not private members,
>> >
>> > Hummm... friend can access private. There is no reserved intimacy for
>> > friend.
> Not according to the test I did about an hour ago.  I declared the function as a
> friend in point3d and defined it in point3d.cpp, and got told off by g++ for
> attempting to access point3d's private members.

because the implementation you provided was not for the one declared as
friend.

It looked like they referred to the same, but it was a totally different
function. Beware of implicit namespaces. (and having "using.." in header
file at global scope is bad practice:  you contaminate every next
included files, as well as the source files)

The only thing a friend does not have access to is inheriting classes :
friendship is not inherited, it has to be reasserted explicitly.


-- 
Just because nobody complains does not mean all parachutes are perfect.


Post a reply to this message

<<< Previous 5 Messages Goto Initial 10 Messages

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.