Forward Declarations - C++

From Visual Basic to GNU C, this is the place to talk programming.

Moderators: SecretSquirrel, just brew it!

Forward Declarations - C++

Postposted on Sun Nov 18, 2007 2:57 pm

I've having trouble with my forward declarations in something that my professor created, called μC++. It's essentially a superlanguage (superset) of C++.

Anyways, we're given the following Makefile:

Code: Select all
-include montype

CXX = u++
CXXFLAGS = -g -Wall -Wno-unused-label -DVOTERTYPE_$(TYPE)
OBJECTS = printer.o voter.o tallyVotes.o driver.o
EXEC = vote

ifeq ($(MONTYPE),$(TYPE))
$(EXEC) : $(OBJECTS)
   $(CXX) $(CXXFLAGS) $(OBJECTS) -o $@
else
ifeq ($(TYPE),)
$(EXEC) : $(OBJECTS)
   $(CXX) $(CXXFLAGS) $(OBJECTS) -o $@
else
.PHONY : $(EXEC)
$(EXEC) :
   rm -f montype
   touch tallyVotes.h
   $(MAKE) TYPE=$(TYPE)
endif
endif

montype :
   echo "MONTYPE:=$(TYPE)" > montype

tallyVotes.o : tallyVotes.h printer.h voter.h tallyVotes$(TYPE).cc
   $(CXX) $(CXXFLAGS) -c tallyVotes$(TYPE).cc -o tallyVotes.o

tallyVotesAUTO.cc : AutomaticSignal.h
printer.o : printer.h voter.h
voter.o : voter.h printer.h tallyVotes.h
driver.o : printer.h voter.h tallyVotes.h

clean :
   rm -f $(OBJECTS) $(EXEC) montype

By reading this, I've extracted the following file names that I have created and added the given code to already:

AutomaticSignal.h
driver.cc
printer.h
printer.cc
tallyVotes.h
tallyVotesAUTO.cc
tallyVotesEXT.cc
tallyVotesINT.cc
tallyVotesSEM.cc
voter.h
voter.cc

Here's the problem: Printer requires an enum from Voter in its header. So I include "voter.h." Voter requires Printer, so I create a forward declaration. It might work if I create a forward declaration for the enum which is in another class, but I don't know how to do that.

When I start working on the source (.cc) for Voter, it says: "invalid use of undefined type 'struct Printer' ". Which implies (to me) that I have to include printer.h in voter.cc. But if I do that, I get a redeclaration of class Voter error.

I know that I'm leaving out a lot of details, especially the interfaces for the classes that I'm trying to compile with. I'm trying to general the problem without providing too many details.

Any help is greatly appreciated.
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Sun Nov 18, 2007 3:03 pm

Can you move that enum to a separate file and let both Printer and Voter include that new file? How tightly coupled are the 2 classes?

You should probably put some code snippets here, but I kind of know what you are doing. If they really need each other may be you can use an abstract class (interface) for this if things get rough. Once you have some code I can help you a bit more.
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24143
Joined: Mon May 24, 2004 1:19 am

Postposted on Sun Nov 18, 2007 3:12 pm

The code that I currently have for those classes are given as interfaces. I don't think that we're allowed to change the member signatures.

The Voter enum is in the constructor of the Printer class and a Printer is in the constructor of the Voter class.

The Voter class also needs a TallyVotes. TallyVotes needs a Printer.

Printer -> Voter::states
TallyVotes -> Printer
Voter -> TallyVotes
Voter -> Printer

These are the dependencies, where the dependent class is on the left.

Let's say I get past the dependencies part. How do I make it so that voter.cc has the ability to call a Printer's members without including the header?
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Sun Nov 18, 2007 3:56 pm

Can't you just #include the files as necessary and then use include guards to make sure they don't get stuck in at two different places?
Core i7 920, 3x2GB Corsair DDR3 1600, 80GB X25-M, 1TB WD Caviar Black, MSI X58 Pro-E, Radeon 4890, Cooler Master iGreen 600, Antec P183, opticals
SNM
Emperor Gerbilius I
 
Posts: 6206
Joined: Fri Dec 30, 2005 9:37 am

Postposted on Sun Nov 18, 2007 4:08 pm

How are the dependencies being linked? By an argument in certain member functions with the concrete type, or a reference/pointer to the type? That can make a difference. But I feel like I may not be explaining this properly. Can you put some code up pretty please? Or just link to your assignment URL. This is not supposed to be hard.

If the classes are given then I think they should be surrounded with include guards?
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24143
Joined: Mon May 24, 2004 1:19 am

Postposted on Sun Nov 18, 2007 4:10 pm

SNM wrote:Can't you just #include the files as necessary and then use include guards to make sure they don't get stuck in at two different places?

I don't think that it makes a difference. If you meant conditional compilation with conditional preprocessors that is.

If I simply include the files, then I end up with a circular inclusion thing. Gmake ends up with an infinite loop of the sorts and exits saying that #include is nested too deeply.

EDIT:

http://www.student.cs.uwaterloo.ca/~cs3 ... ssign5.pdf

It's Question 3.
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Sun Nov 18, 2007 4:13 pm

Asin wrote:If I simply include the files, then I end up with a circular inclusion thing. Gmake ends up with an infinite loop of the sorts and exits saying that #include is nested too deeply.


You could always add the following item to the include files. Its pretty much a rapper for your include files. It will prevent the circular inclusion, but it might be best to clean up your includes.

Code: Select all
#ifndef SOMETHING_H
#define SOMETHING_H

(everything in H file)

#endif
tfp
Grand Gerbil Poohbah
 
Posts: 3066
Joined: Wed Sep 24, 2003 10:09 am

Postposted on Sun Nov 18, 2007 4:20 pm

In a nutshell, I've got the following:

printer.h:

Code: Select all
class Printer {
  public:
    void print( Voter::states state );
};


tallyVotes.h:

Code: Select all
class TallyVotes {
  public:
    TallyVotes( Printer &prt );
};


voter.h:

Code: Select all
class Voter {
  public:
    enum states { A, B };
    Voter( TallyVotes &voteTallier, Printer& prt );
};


From here, I'm not quite sure what to do with the includes. Anything I do seems to still lead to some sort of undefined error, or invalid use error, or my initial printer.o and voter.o files missing error. That last part is something that I already fixed, I think.
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Sun Nov 18, 2007 4:27 pm

tfp wrote:You could always add the following item to the include files. Its pretty much a rapper for your include files. It will prevent the circular inclusion, but it might be best to clean up your includes.

Code: Select all
#ifndef SOMETHING_H
#define SOMETHING_H

(everything in H file)

#endif

Yes, that's an include guard.
Core i7 920, 3x2GB Corsair DDR3 1600, 80GB X25-M, 1TB WD Caviar Black, MSI X58 Pro-E, Radeon 4890, Cooler Master iGreen 600, Antec P183, opticals
SNM
Emperor Gerbilius I
 
Posts: 6206
Joined: Fri Dec 30, 2005 9:37 am

Postposted on Sun Nov 18, 2007 4:29 pm

I will just have to say that if production code requires so much effort just to sort out include dependencies this is probably bad smell already. But let's just focus on the problem at hand.

Printer's dependency on the enum does not require a forward declaration of Voter I think. You just need to include voter.h to get the enum type declaration. Voter.h does need forward declaration for Printer and TallyVotes. So try play with that to see if you can get somewhere?

PS. I assume you did get your include guards right, right?

PPS. LOL I was browsing that CSC343 site already, Google FTW.
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24143
Joined: Mon May 24, 2004 1:19 am

Postposted on Sun Nov 18, 2007 4:38 pm

There's a simple solution for the redeclaration issue. Use this in all of your .h files:

#ifndef _H_VOTER_H
#define


code goes here


#endif

So, basically, you need to wrap around your header code in a ifdef block, so when someone includes it again, you won't get the redeclaration issue. Of course, you need one different ifdef namescope for each .h file, say _H_VOTER_H for voter.h, _H_PRINTER_H for printer.h and so fourth.
Last edited by radix on Sun Nov 18, 2007 4:40 pm, edited 1 time in total.
radix
Gerbil First Class
 
Posts: 103
Joined: Sun Jan 13, 2002 6:00 pm
Location: Mountain View, CA

Postposted on Sun Nov 18, 2007 4:40 pm

Nope, no include guards. Don't quite know how to use them since the only thing defined is TYPE ( { SEM, EXT, INT, AUTO } ) from the command line.

Do I just make my own variables, or can I do an #ifndef Printer for example?
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Sun Nov 18, 2007 4:42 pm

radix wrote:There's a simple solution for the redeclaration issue. Use this in all of your .h files:

#ifndef _H_VOTER_H
#define


code goes here


#endif

So, basically, you need to wrap around your header code in a ifdef block, so when someone includes it again, you won't get the redeclaration issue. Of course, you need one different ifdef namescope for each .h file, say _H_VOTER_H for voter.h, _H_PRINTER_H for printer.h and so fourth.

Ah, I have seen that before. I'll try it.

I didn't include it due to my lack of C++ experience and because I thought that the dependencies in the Makefile would take care of all that.
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Sun Nov 18, 2007 4:49 pm

Asin wrote:I didn't include it due to my lack of C++ experience and because I thought that the dependencies in the Makefile would take care of all that.

That's not even remotely the purpose of makefiles. The dependencies defined there simply tell the Make program which files are dependent on which others so it knows which to recompile after one file has been changed. It's kind of a moot point in the kind of thing you're likely to do school assignments for, but in a production environment where a full recompile can take multiple hours it means that if you only change one module you can recompile in 15 minutes instead of 1500.
Core i7 920, 3x2GB Corsair DDR3 1600, 80GB X25-M, 1TB WD Caviar Black, MSI X58 Pro-E, Radeon 4890, Cooler Master iGreen 600, Antec P183, opticals
SNM
Emperor Gerbilius I
 
Posts: 6206
Joined: Fri Dec 30, 2005 9:37 am

Postposted on Sun Nov 18, 2007 4:59 pm

Yeah, didn't work out so well.

I have this in place of forward declarations:

Code: Select all
#ifndef __PRINTER_H
_Cormonitor Printer;
#else
#include "printer.h"
#endif


And I have

Code: Select all
#ifndef __PRINTER_H
#define __PRINTER_H
...
#endif


around the code for the printer.h file, in this example.
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Sun Nov 18, 2007 6:04 pm

Include guards and incomplete types are 2 different things. Get your include guard working first (remember to use different symbols for different header files, like _VOTER_H, _TALLYVOTE_H, and _PRINTER_H), then see if you have a problem.

BTW, you should be able to look at any C/C++ header files on your system to find examples of how to do a proper include guard.
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24143
Joined: Mon May 24, 2004 1:19 am

Postposted on Sun Nov 18, 2007 6:29 pm

Well, I eventually got it to work after speaking with a friend of mine for a while.

I overlooked the fact that I could have other includes in the .cc file beyond the .h file.

So I was trying to include everything that I needed in the header file or make forward declarations. It most likely died with invalid use errors because I didn't include the header in the .cc after using a forward declaration.
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Sun Nov 18, 2007 6:34 pm

Glad you have got that working. To the uninitiated this stuff can be a bit weird. I didn't get incomplete class declarations forwarding at first too. Used correctly it can help you reduce the number of header files included in a header file thus reducing build dependencies and help promote somewhat better interface design.
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24143
Joined: Mon May 24, 2004 1:19 am

Postposted on Sun Nov 18, 2007 6:52 pm

What's odd is that I was somewhat exposed to this in Grade 11 when we were using C++. We had just graduated from Turing and I knew nothing about Java.

We had the notion of function prototypes which is essentially forward declarations for functions. When classes come into the picture and after a 5 or 6 year hiatus on Java, I guess that you start to lose some of the ideas that you were taught. Not knowing that such things exist doesn't help either. :P
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Sun Nov 18, 2007 8:14 pm

radix wrote:#ifndef _H_VOTER_H

Just a nitpick, but it's bad form to use macros that start with an underscore followed by a capital letter or double underscores, because the C standard says such names are reserved for internal use by the language implementation (compiler/library/etc.).
bitvector
Grand Gerbil Poohbah
 
Posts: 3234
Joined: Wed Jun 22, 2005 3:39 pm
Location: Mountain View, CA

Postposted on Sun Nov 18, 2007 8:54 pm

Asin wrote:What's odd is that I was somewhat exposed to this in Grade 11 when we were using C++. We had just graduated from Turing and I knew nothing about Java.

We had the notion of function prototypes which is essentially forward declarations for functions. When classes come into the picture and after a 5 or 6 year hiatus on Java, I guess that you start to lose some of the ideas that you were taught. Not knowing that such things exist doesn't help either. :P
There's a reason why I kept 10+ year old code around for reminiscing and reference purposes. 8)
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24143
Joined: Mon May 24, 2004 1:19 am

Postposted on Mon Nov 19, 2007 1:15 pm

bitvector wrote:
radix wrote:#ifndef _H_VOTER_H

Just a nitpick, but it's bad form to use macros that start with an underscore followed by a capital letter or double underscores, because the C standard says such names are reserved for internal use by the language implementation (compiler/library/etc.).

I thought that I saw those double underscores somewhere before. That's why I thought that was the convention. Oh well.
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Mon Nov 19, 2007 1:21 pm

Asin wrote:
bitvector wrote:
radix wrote:#ifndef _H_VOTER_H

Just a nitpick, but it's bad form to use macros that start with an underscore followed by a capital letter or double underscores, because the C standard says such names are reserved for internal use by the language implementation (compiler/library/etc.).

I thought that I saw those double underscores somewhere before. That's why I thought that was the convention. Oh well.
I believe double underscore is fine. Single and then followed by a capital letter is not. That's what bitvector was saying.
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24143
Joined: Mon May 24, 2004 1:19 am

Postposted on Mon Nov 19, 2007 1:38 pm

Flying Fox wrote:
Asin wrote:
bitvector wrote:
radix wrote:#ifndef _H_VOTER_H

Just a nitpick, but it's bad form to use macros that start with an underscore followed by a capital letter or double underscores, because the C standard says such names are reserved for internal use by the language implementation (compiler/library/etc.).

I thought that I saw those double underscores somewhere before. That's why I thought that was the convention. Oh well.
I believe double underscore is fine. Single and then followed by a capital letter is not. That's what bitvector was saying.

No, that's not what I said. Double underscores are reserved for the implementation as is a single underscore followed by a capital letter. A single underscore followed by a lowercase letter or a digit is reserved for file scoped identifiers.

Asin wrote:I thought that I saw those double underscores somewhere before. That's why I thought that was the convention. Oh well.

You've probably seen them in places like __FILE__ or __STDC__ . Or things like __STRICT_ANSI__ or _POSIX_SOURCE or _POSIX_C_SOURCE. Those are all in the reserved identifier space and used by the implementation.
bitvector
Grand Gerbil Poohbah
 
Posts: 3234
Joined: Wed Jun 22, 2005 3:39 pm
Location: Mountain View, CA

Postposted on Mon Nov 19, 2007 9:29 pm

AH, CS343, how I miss thee....

Getting the forward declarations and interdependencies right was actually one of the hardest parts of those assignments. Don't be afraid of your TAs.

Is Kierstead still around? If she is, I know she seams like a heartless woman, but she will help you out, so don't be afraid to ask her if you're having some trouble. And Burh is awsome, and you can definitly talk with him too. One of the best profs I had there.
emorgoch
Gerbil Elite
 
Posts: 686
Joined: Tue Mar 27, 2007 10:26 am
Location: Toronto, ON

Re: Forward Declarations - C++

Postposted on Tue Nov 20, 2007 12:16 am

Asin wrote:I've having trouble with my forward declarations in something that my professor created, called μC++. It's essentially a superlanguage (superset) of C++.

Hrm, I was wondering... why is it called micro C++ if it is a superset of C++?
bitvector
Grand Gerbil Poohbah
 
Posts: 3234
Joined: Wed Jun 22, 2005 3:39 pm
Location: Mountain View, CA

Re: Forward Declarations - C++

Postposted on Tue Nov 20, 2007 12:49 am

bitvector wrote:Hrm, I was wondering... why is it called micro C++ if it is a superset of C++?

Well... "μ" doesn't always mean "micro". Maybe it is actually Muon C++? :lol:
(this space intentionally left blank)
just brew it!
Administrator
Gold subscriber
 
 
Posts: 36922
Joined: Tue Aug 20, 2002 9:51 pm
Location: Somewhere, having a beer

Postposted on Tue Nov 20, 2007 2:10 am

bitvector wrote:
Asin wrote:I thought that I saw those double underscores somewhere before. That's why I thought that was the convention. Oh well.
You've probably seen them in places like __FILE__ or __STDC__ . Or things like __STRICT_ANSI__ or _POSIX_SOURCE or _POSIX_C_SOURCE. Those are all in the reserved identifier space and used by the implementation.

Maybe. I also vaguely remember something about __uuint32 or something as an unsigned integer type in Microsoft Visual C++ which is what we used in Grade 11. I do remember that in order to get the IDE to give it a blue colour, we needed two underscores. Our teacher and I were looking at it together trying to figure out why it wasn't being recognized with just one underscore.

Obviously, not the same since we were talking about definitions.

bitvector wrote:Is Kierstead still around? If she is, I know she seams like a heartless woman, but she will help you out, so don't be afraid to ask her if you're having some trouble. And Burh is awsome, and you can definitly talk with him too. One of the best profs I had there.

The name sounds familiar, don't quite recall meeting her though.

Buhr is cool, although I haven't had to talk to him personally yet. Been procrastinating way too much this term to actually get anything done. Even as I type this, I have a 10 page essay due tomorrow that isn't done. :P

The latest Instructional Coordinator was Chris Ingram, but Buhr announced that Chris has accepted another job just last week actually.

bitvector wrote:Hrm, I was wondering... why is it called micro C++ if it is a superset of C++?

Searching around seems to turn up information on μSystem, of which μC++ is a part of. I guess that the "micro" part is just coming from the μSystem project, whatever that is. Or, it's "micro" because μC++ is just a translator that turns source code into C++ and then uses the platform's C++ compiler.
Asin
Gerbil Team Leader
 
Posts: 291
Joined: Tue Mar 09, 2004 9:36 pm
Location: Ontario, Canada

Postposted on Tue Nov 20, 2007 7:53 am

Asin wrote:Or, it's "micro" because μC++ is just a translator that turns source code into C++ and then uses the platform's C++ compiler.

That's funny... C++ originally started out as a translator which produced C, which was then compiled by the platform's native C compiler. So perhaps this new language should actually be called C++++? :D
(this space intentionally left blank)
just brew it!
Administrator
Gold subscriber
 
 
Posts: 36922
Joined: Tue Aug 20, 2002 9:51 pm
Location: Somewhere, having a beer

Postposted on Tue Nov 20, 2007 7:55 am

just brew it! wrote:
Asin wrote:Or, it's "micro" because μC++ is just a translator that turns source code into C++ and then uses the platform's C++ compiler.

That's funny... C++ originally started out as a translator which produced C, which was then compiled by the platform's native C compiler. So perhaps this new language should actually be called C++++? :D
C++++ turned into C# according to "what I heard"? :lol:
Image
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
Flying Fox
Gerbil God
 
Posts: 24143
Joined: Mon May 24, 2004 1:19 am

Next

Return to Developer's Den

Who is online

Users browsing this forum: No registered users and 2 guests