I don't know what's wrong with my very simple code

S

Sam

Hi I'm learning to code with C++ and wrote some very simple code. I
think it's consistent with every rule but always got compiling errors
that I don't understand.

The code include 5 files as following, delimited by //////:

////////////////pose.h
#ifndef pose_h
#define pose_h
#include "point.h"
class pose
{
int i;
public:
friend void point::init(pose P);
};
#endif

////////////////pose.cpp
#include "pose.h"

////////////////point.h
#ifndef point_h
#define point_h
#include "pose.h"
class point
{
public:
void init(pose P);
};
#endif

////////////////point.cpp
#include "point.h"
void point::init(pose P)
{
P.i=1;
}

////////////////main.cpp
#include "pose.h"
#include "point.h"
void main()
{
}


Basically the "point" class has a function to modify the "pose"
object's private data "i". VC++ always gives the error messages like:
'point' : is not a class or namespace name
'i' : cannot access private member declared in class 'pose'
syntax error : identifier 'pose'
nonexistent function 'point::init' specified as friend

I cannot understand it. Could anybody tell me what he thinks of it?
Thanks a lot.
 
J

Jakob B. Olsen

A friend function can not be a member of a class. So point::init can not be
a friend to pose.

Jakob
 
A

Adam Fineman

osmium said:
Sam writes:




i is, by default private. Which is what the compiler told you. Good
practice says it *should be* private. Use a friend class/function or use an
accessor to fiddle with the value of i. For a real program you should
probably rethink your overall design.

You are on the verge of developing some bad habits.
The design issue aside, the OP's question is about why the friend
declaration doesn't work as he thinks it should. He knows that i is
private, and he did have a friend function declared.

To the OP, you could get around your problem by using a combination of a
reference parameter and a forward declaration:

////////////////////////////////////////////////////////////////////////////
// A.hpp
#ifndef A_HPP_INCLUDED
#define A_HPP_INCLUDED

#include "B.hpp"

class A
{
/* ... */
friend void B:f(A& a); // A forward declaration does not suffice
// here; you must have the full definition
// of B, hence the #include above.
/* ... */
};

#endif // include guard

////////////////////////////////////////////////////////////////////////////
// B.hpp
#ifndef B_HPP_INCLUDED
#define B_HPP_INCLUDED

class A; // forward declaration

class B
{
/* ... */
public:
void f(A& a); // Note that for a reference or pointer
// to A, you only need the forward
// declaration, not the full class
// definition.

/* ... */
};


The reason what you tried earlier didn't work is that your include
directives would have resulted in a circular dependency, which your
include guard prevented. (That's what include guards are for, after all.)

If you can't use a reference parameter, then you will have to try
something else -- like a public accessor method in class A. However,
you should prefer to pass classes by reference in most situations, as
passing by value invokes the class' copy constructor. Note that in that
case, the function would only modify a copy of the parameter anyway,
which is almost certainly not what you want.

HTH,

- Adam
 
B

Brian MacBride

Sam said:
Hi I'm learning to code with C++ and wrote some very simple code. I
think it's consistent with every rule but always got compiling errors
that I don't understand.

The code include 5 files as following, delimited by //////:

////////////////pose.h
#ifndef pose_h
#define pose_h
#include "point.h"
class pose
{
int i;
public:
friend void point::init(pose P);
};
#endif

////////////////pose.cpp
#include "pose.h"

////////////////point.h
#ifndef point_h
#define point_h
#include "pose.h"
class point
{
public:
void init(pose P);
};
#endif

////////////////point.cpp
#include "point.h"
void point::init(pose P)
{
P.i=1;
}

////////////////main.cpp
#include "pose.h"
#include "point.h"
void main()
{
}


Basically the "point" class has a function to modify the "pose"
object's private data "i". VC++ always gives the error messages like:
'point' : is not a class or namespace name
'i' : cannot access private member declared in class 'pose'
syntax error : identifier 'pose'
nonexistent function 'point::init' specified as friend

I cannot understand it. Could anybody tell me what he thinks of it?
Thanks a lot.

//////////////// pose.h
#ifndef pose_h
#define pose_h

#include "point.h"
class pose {
int i;
friend void point::init (pose &P);
};

#endif

//////////////// point.h
#ifndef point_h
#define point_h

class pose;

class point {
public:
void init (pose &);
};

#endif

//////////////// pose.cpp
#include "pose.h"

//////////////// point.cpp

#include "point.h"
#include "pose.h"

void point::init (pose &P) {
P.i = 1;
}

//////////////// main.cpp

#include "pose.h"
#include "point.h"
int main () {
pose p;
point pt;
pt.init (p);
}

I think you mean to pass the 'pose' by reference? As others have mentioned,
there are probably better ways of achieving your goal here.

Regards

Brian
 
O

osmium

Sam said:
Hi I'm learning to code with C++ and wrote some very simple code. I
think it's consistent with every rule but always got compiling errors
that I don't understand.

The code include 5 files as following, delimited by //////:

////////////////pose.h
#ifndef pose_h
#define pose_h
#include "point.h"
class pose
{
int i;

i is, by default private. Which is what the compiler told you. Good
practice says it *should be* private. Use a friend class/function or use an
accessor to fiddle with the value of i. For a real program you should
probably rethink your overall design.

You are on the verge of developing some bad habits.
 
S

Sam

Jakob B. Olsen said:
A friend function can not be a member of a class. So point::init can not be
a friend to pose.

Jakob

I checked it out from the book "thinking in c++" finding that a friend
fn can be a member of a class.

Now I think the problem might be, whichever class is compiled first,
it needs the info of the the other class. When it goes to the other
class, it finds that it needs the previous class. That's the way I
understand it because I switched the order of compiling classes but
always found the compiler thinks the class (or class member fn) is not
defined.

Sam
 
A

Amitashk

In file point.cpp, the first line of code is:

#include "point.h"

Try changing it to:

#include "pose.h"
 
T

tom_usenet

Hi I'm learning to code with C++ and wrote some very simple code. I
think it's consistent with every rule but always got compiling errors
that I don't understand.

The code include 5 files as following, delimited by //////:

////////////////pose.h
#ifndef pose_h
#define pose_h
#include "point.h"
class pose
{
int i;
public:
friend void point::init(pose P);
};
#endif

////////////////pose.cpp
#include "pose.h"

////////////////point.h
#ifndef point_h
#define point_h
#include "pose.h"

The above line shouldn't be there - it introduces a circular
dependency (pose.h depends on point.h which in turn depends on pose.h
and so on). Instead, just use a forward declaration:
class pose;
class point
{
public:
void init(pose P);

I think you intended to pass by reference:

void init(pose& P);
};
#endif

////////////////point.cpp
#include "point.h"

and here you now need:
#include "pose.h" //need complete definition of pose.
void point::init(pose P)
{
P.i=1;
}

////////////////main.cpp
#include "pose.h"
#include "point.h"
void main()
{
}

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
D

dwizard

#ifndef point_h
#define point_h

#include "pose.h"

class pose; // <--------- ADD THIS forward decleration

class point
{
public:
void init(pose P);
};

#endif
 
S

Sam

tom_usenet said:
The above line shouldn't be there - it introduces a circular
dependency (pose.h depends on point.h which in turn depends on pose.h
and so on). Instead, just use a forward declaration:
class pose;

Thank you Tom. I tried it. You're right and you got the problem - a
circular dependency.
A forward declaration "class pose" should appear in point.h, and then
"#include pose.h" should be in point.cpp so the circular dependency is
avoided.
I think you intended to pass by reference:

void init(pose& P);

I don't understand why everyone wants to pass by reference. Why not
just pass by object. It works.
 
S

Sam

tom_usenet said:
The above line shouldn't be there - it introduces a circular
dependency (pose.h depends on point.h which in turn depends on pose.h
and so on). Instead, just use a forward declaration:
class pose;


I think you intended to pass by reference:

void init(pose& P);
I just want to make it clearer. Here the fn init(pose P) is a friend
of pose, so it can modify P's private values. It does not have to use
reference to modify P's private values.
 
T

tom_usenet

I don't understand why everyone wants to pass by reference. Why not
just pass by object. It works.

Let's take a look at the definition of init:

init seems to want to assign 1 to P.i. If P is passed by value, the
change will be made to a local copy of P, and the pose from the call
site will be unmodified. In other words, the function as written is a
no-op. Read up on pass-by-reference vs. pass-by-value. There should be
some FAQs about it (see my sig).

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
M

Martijn Lievaart

#ifndef point_h
#define point_h

#include "pose.h"

class pose; // <--------- ADD THIS forward decleration

class point
{
public:
void init(pose P);
};

#endif

Won't work. Needs a complete definition of the class to pass to init, a
forward declaration will not do.

HTH,
M4
 
A

Adam Fineman

Martijn said:
Won't work. Needs a complete definition of the class to pass to init, a
forward declaration will not do.

HTH,
M4
Besides that, once you've included the header that provides a full
declaration of a class, providing a forward declaration of that class
afterwards does absolutely nothing.

- Adam
 
K

Karl Heinz Buchegger

Sam said:
I just want to make it clearer. Here the fn init(pose P) is a friend
of pose, so it can modify P's private values. It does not have to use
reference to modify P's private values.

Right.
But that init function is called from somewhere. Eg.

int main()
{
point A;
pose B;

A.init( B );

Well. As you have written it now, a copy of B is made and given to init().
init() now modifes this copy. But this also means that B is never touched
and modified. In some situations this is indeed what someone wants to
achieve, but most of the time it is not. More often you want the function
to change the object given to it. In this case you have to use a reference.

Also: make it a habit of yours to pass class objects by reference.
If you want the function to able to change the callers object, you
use an ordinary reference:

void point::init( pose& Arg )
{
Arg.i = 2;
}

If you don't want the function to be able to change the callers argument,
you pass by const reference:

void point::init( const pose& Arg )
{
Arg.i = 2;
}

Now the compiler will emit an error, saying that i of Arg cannot be changed,
since you promised that it is const - non changable.

The reason why you want to pass a reference is, that when you pass by value

void point::init( pose Arg )

a copy of the callers pose object is made. Depending on the object itself this
can be a (very) costly operation. Well in your case the pose object seems to
be simple enough that this would not be a problem, but there is more to it:
The pass by reference doesn't cost you much more then creating a copy of the
object, so it doesn't really matter which one you choose (in this example). Therefore
you are in the situation: in the worst case, both passing mechanisms are cost equal
but in the best case the pass by reference saves you from a costly operation. So use
pass by reference and be on the safe side at all times.

The only exception is: If you definitly don't want to change the callers argument,
but yet have to work with that object and change it locally in that function, you can
use a pass by value. But even then it is arguable if one should pass per const reference
and create the copy explicitely to document the feature that you know what you are
doing and you know that the change is not reflected to the caller of that function:

void point::init( const pose& Arg )
{
pose ArgCopy( Arg ); // creating a copy of what the caller passed

ArgCopy.i = 3; // I know that the assignment takes place at a
// copy of whatever the caller has passed to this
// function and thus the assignment will not be reflected
// to outside this function
}
 
B

Brian MacBride

Martijn Lievaart said:
Won't work. Needs a complete definition of the class to pass to init, a
forward declaration will not do.

HTH,
M4

Say what?

We are only at the declaration stage above. 'point' will have to know all
about 'pose' at implementation but not necessarily at declaration. Consider
all one file...

class pose;

class point {
public:
void init (pose &);
};

class pose {
int i;
friend void point::init (pose &);
};

void point::init (pose &P) {
P.i = 1;
}

int main () {
pose p;
point pt;
pt.init (p);
}

As discussed elsewhere, we probably want to pass 'pose' by reference.

Regards

Brian
 
M

Martijn Lievaart

As discussed elsewhere, we probably want to pass 'pose' by reference.

No, we /have/ to pass by reference, otherwise point will not compile.
Without the reference, if we pass by value, point must know the size of a
pose, a forward declaration will not suffice.

M4
 
B

Brian MacBride

Martijn Lievaart said:
No, we /have/ to pass by reference, otherwise point will not compile.
Without the reference, if we pass by value, point must know the size of a
pose, a forward declaration will not suffice.

M4

class pose;

class point {
public:
void init (pose);
};

class pose {
int i;
friend void point::init (pose);
};

void point::init (pose P) {
P.i = 1;
}

int main () {
pose p;
point pt;
pt.init (p);
}

Are you telling me that the above will not compile?

Regards

Brian
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top