mutual class dependencies

M

mosfet

Hi,

I would like to write something like :

//forward declarations
class B;
class A;


class A
{
public:
A()
{

}

A& SetContext(B::TContext eContext)
{
m_eContext = eContext;
return *this;
}

B::TContext m_eContext;
};


class B:
{
public:

enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount
};
}:

But When I try I Get error C2027: use of undefined type 'B'
 
A

Alf P. Steinbach

* mosfet:
Hi,

I would like to write something like :

//forward declarations
class B;
class A;


class A
{
public:
A()
{

}

A& SetContext(B::TContext eContext)
{
m_eContext = eContext;
return *this;
}

B::TContext m_eContext;
};


class B:
{
public:

enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount
};
}:

But When I try I Get error C2027: use of undefined type 'B'

Remove the forward declarations.

Move class B before class A.

Fix the syntax errors.


Cheers, & hth.,

- Alf
 
A

AnonMail2005

Hi,

I would like to write something like :

//forward declarations
class B;
class A;

class A
{
public:
        A()
        {

        }

        A& SetContext(B::TContext eContext)
        {
                m_eContext = eContext;
                return *this;
        }

B::TContext m_eContext;

};

class B:
{
public:

enum TContext
        {
                EUserMessage = 0,
                EWizzardQuestion,
                EWizzardConfirmation,
                EContextCount
        };

}:

But When I try I Get error C2027: use of undefined type 'B'

You use B as a member of A so the compiler needs to have the
complete declaration of B.

You can include the B header file (instead of forward declaring
it). Also, possible solution is to have A contain a pointer to
B instead of a B.

HTH
 
M

mosfet

Alf P. Steinbach a écrit :
* mosfet:

Remove the forward declarations.

Move class B before class A.

Fix the syntax errors.


Cheers, & hth.,

- Alf
Oups I forgot to say that class B includes a A object:


class A
{
public:
A()
{

}

A& SetContext(B::TContext eContext)
{
m_eContext = eContext;
return *this;
}

B::TContext m_eContext;
};



class B:
{
public:
enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount
};

protected:

A m_A;

}:


So I cannot do what you say.
 
A

Alf P. Steinbach

* mosfet:
Alf P. Steinbach a écrit :
Oups I forgot to say that class B includes a A object:


class A
{
public:
A()
{

}

A& SetContext(B::TContext eContext)
{
m_eContext = eContext;
return *this;
}

B::TContext m_eContext;
};



class B:
{
public:
enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount
};

protected:

A m_A;

}:


So I cannot do what you say.

Oups I forgot to say that if the requirements change, change the
solution accordingly.


Cheers, & hth.

- Alf


PS: Don't forget to fix the syntax errors.
 
S

Salt_Peter

Alf P. Steinbach a écrit :







Oups I forgot to say that class B includes a A object:

class A
{
public:
A()
{

}

A& SetContext(B::TContext eContext)
{
m_eContext = eContext;
return *this;
}

B::TContext m_eContext;

};

class B:
{
public:
enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount

};

protected:

A m_A;

}:

So I cannot do what you say.

...unfortunately for you.
If type A has a member B and a type B has a member A (which has a B
which has an A .... ad infinitum) then the program has no way to
define concretely the resulting type.

However, you could have a type A as a member of type B and use a
pointer to B in type A.
 
P

Puppet_Sock

Alf P. Steinbach a écrit :









Oups I forgot to say that class B includes a A object:

class A
{
public:
     A()
     {

     }

     A& SetContext(B::TContext eContext)
     {
         m_eContext = eContext;
         return *this;
     }

B::TContext m_eContext;

};

class B:
{
public:
enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount

};

protected:

A  m_A;

}:

So I cannot do what you say.

And, of course, the world would come to an end if you moved
that enum out of class B.
Socks
 
P

Phil Endecott

class A
{
public:
A()
{

}

A& SetContext(B::TContext eContext)
{
m_eContext = eContext;
return *this;
}

B::TContext m_eContext;
};



class B:
{
public:
enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount
};

protected:

A m_A;

}:

You need to break the circular dependencies somewhere, and there are
several options. How about:

enum B_TContext { EUserMessage = 0 ...... };

class A {
A& SetContext(B_TContext eContent) ....
B_TContext m_eContext;
};

class B {
typedef B_TContext TContext;
A m_A;
};
 
J

jalina

Puppet_Sock a écrit :
And, of course, the world would come to an end if you moved
that enum out of class B.
Socks

People answering in this newsgroup is so nice and well minded.

Everyone who is a newbye or not aware of usenet usage have such
"pleasant" answers from some people that are so clever (and certainly
think that the noobs posting dumb....s only deserve contempt - just read
their "nice" answers)

Perhaps rename this newgroup to something like comp.land.advanced.c++ so
that noobs don't get to post there. I guess that between clever people,
contempt does not matter.

I have decided to boycott this newsgroup and I am going to start an
campaign to inform people not to read and post here.

Jalina
 
J

jalina

Alf P. Steinbach a écrit :
* mosfet:

Oups I forgot to say that if the requirements change, change the
solution accordingly.


Cheers, & hth.

- Alf


PS: Don't forget to fix the syntax errors.
People answering in this newsgroup is so nice and well minded.

Everyone who is a newbye or not aware of usenet usage have such
"pleasant" answers from some people that are so clever (and certainly
think that the noobs posting dumb....s only deserve contempt - just read
their "nice" answers)

Perhaps rename this newgroup to something like comp.land.advanced.c++ so
that noobs don't get to post there. I guess that between clever people,
contempt does not matter.

I have decided to boycott this newsgroup and I am going to start an
campaign to inform people not to read and post here.

Jalina
 
C

Chris Thomasson

[...]
I have decided to boycott this newsgroup and I am going to start an
campaign to inform people not to read and post here.

Don't you have any other ways to waste your time?
 
J

James Connell

jalina said:
I have decided to boycott this newsgroup and I am going to start an
campaign to inform people not to read and post here.

start now - you posted this message twice already.
 
A

anon

jalina said:
I have decided to boycott this newsgroup and I am going to start an
campaign to inform people not to read and post here.

Cool. Start with nike sellers, free sex messages, free money sites, and
similar people.
 
A

Alf P. Steinbach

* anon:
Cool. Start with nike sellers, free sex messages, free money sites, and
similar people.

Well, I think "jalina" had a point, although he/she may not have and
probably have not (yet) realized it.

Namely, that reading a technical discussion as if it were emotional
hinting and come-uppance (not that it isn't, sometimes!) is in general
very counter-productive. Technical accuracy is very important for
technical stuff. And as it happens, which is a bit ironic, that was my
message.

FAQ item 5.8 "How do I post a question about code that doesn't work
correctly", found at e.g. <url:
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8>, gives
some concrete advice about how to achieve technical accuracy when
posting, and hence ensuring more accurate answers and not wasting
other's time, and perhaps I should just have referred to that FAQ item
(I would if I'd known there was such a sensitive reader lurking! :) ).

Cheers,

- Alf
 
G

Grizlyk

mosfet said:
class B includes a A object:

It is evidently, you need TContext type completely declared, because
of you need to know sizeof(TContext) to pass eContext by value.

You can pass eContext by reference
A& SetContext(B::TContext& eContext)

or remove declaration of TContext into separated class

namespace NB{
class TContext
{
//
};
}

//forward declarations
class A;
class B;
//using NB::TContext;

Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new
 
E

EventHelix.com

Alf P. Steinbach a écrit :







Oups I forgot to say that class B includes a A object:

class A
{
public:
     A()
     {

     }

     A& SetContext(B::TContext eContext)
     {
         m_eContext = eContext;
         return *this;
     }

B::TContext m_eContext;

};

class B:
{
public:
enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount

};

protected:

A  m_A;

}:

So I cannot do what you say.

Include A and B as references. That way you can use forward
declarations to take care of the cyclic dependencies.

The following article should help:
http://www.eventhelix.com/RealtimeMantra/HeaderFileIncludePatterns.htm
 
G

Grizlyk

jalina said:
I have decided to boycott this newsgroup and I am going to start an
campaign to inform people not to read and post here.

Do not pay any attention at the rancorous men, just because:
1. they cheafly do not give you any useful in C++ scope;
2. it is not easy for anybody (though i do not acquit any evil
behavior) to read and answer in a group, especially when there are
tons of questions, that can be easy answered without any questions by
posters itself.

Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new
 
G

Grizlyk

Grizlyk said:
You can pass eContext by reference
A& SetContext(B::TContext& eContext)

Well, looks like useless advice here, because B::TContext must be
declared. You can not declare B::TContext like this (i do not know
why)

class B;
//using B::C;
//class B::C;

but you can use template<> to delay declaration

template<typename T=B>
class A
{
public:
A& SetContext(T::TContext& eContext);
};

template<typename T> //(T=B is not allowed)
void ::foo(T::TContext& c)
{
A<T> a;
a.SetContext(c);
}

class B
{
public:
//can be declared only for references
class TContext;
};

void ::boo(B::TContext& c)
{
or remove declaration of TContext into separated class

And yet, instead of using B::TContext& reference, you can move body of
SetContext function outside of class A scope and place the body after
B::TContext complete declaration, but the declaration of SetContext
with eContext passed by value will touch you in code like this

void ::foo(B::TContext& b)
{
A a;
a.SetContext(b);
}

if the code ::foo will be placed befor B::TContext complete
declaration.

Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new
 
P

Pavel

mosfet said:
Alf P. Steinbach a écrit :
Oups I forgot to say that class B includes a A object:


class A
{
public:
A()
{

}

A& SetContext(B::TContext eContext)
{
m_eContext = eContext;
return *this;
}

B::TContext m_eContext;
};



class B:
{
public:
enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount
};

protected:

A m_A;

}:


So I cannot do what you say.

That is an interesting problem, actually. Mixing in some templates
compiled for me (not that I enjoyed using templates for the wrong cause):

template<typename ThatEnum>
class A_GENERIC {
public: A_GENERIC() {}

A_GENERIC &
SetContext(ThatEnum eContext)
{
m_eContext = eContext;
return *this;
}

ThatEnum m_eContext;
};

class B
{
public:
enum TContext
{
EUserMessage = 0,
EWizzardQuestion,
EWizzardConfirmation,
EContextCount
};

protected:

A_GENERIC<B::TContext> m_A;

};


typedef A_GENERIC<B::TContext> A;

// at this point, we have regular (non-template) A, B and B::TContext as
ordered..

int main(int argc, char *argv[]) {
A a;
a.SetContext(B::EUserMessage);
B b;
return 0;
}

Hope this will help -- but I wonder if there can be a non-template solution.

-Pavel
 

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

Forum statistics

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

Latest Threads

Top