Skip to main content
gamedev.net
🔒 Locked

Using enums in function declarations

Started by JD 8 replies 250+ views
Original Post
JD
JD
To avoid header circular dependancy I write int in the function declaration instead of using enum name like this: ------------------------------ // foo.h file #include "bar.h" class Foo { public: enum BOOL {FALSE, TRUE}; }; ------------------------------ // bar.h file class Bar { public: void Fun(int boolval); }; // bar cpp file #include "foo.h" void Bar::Fun(BOOL boolval){} --------------------------------------------------- Is there a better way to do this so that I could write Fun(BOOL boolval) instead? Thanks.
HG
HG
Typically you would use #IFNDEF pairs. The way I'd do this trivial example is:

foo.h:

#ifndef FOO_H
#define FOO_H

class Foo
{
public:
enum BOOL {FALSE, TRUE};
};

#endif

bar.h:

#ifndef BAR_H
#define BAR_H

#include "foo.h"

class Bar
{
public:
void Fun(Foo::BOOL boolval);
};

#endif

bar.cpp:

#include "bar.h"

void Bar::Fun(Foo::BOOL boolval);

Of course, the best way of doing it is to make your enumerations a typedef in a header, protected by the #ifndef blocks, that you include where necessary.

Structure is good - if something is needed in multiple places, put it in its own header. If you like, have one class per file!

[edited by - HG on January 5, 2003 1:39:21 PM]
-Richard
Qw3r7yU10p!
Qw3r7yU10p!
there''s not much point enumerating booleans as its already a built in keyword for c++.

however passing a boolean is a sure-fire way to make it difficult to remember exactly what your interface does. so enumerations can communicate useful information and become part of the documentation for the interface

so

enum fillings { strawberry, applesauce, chickenCurry };

or

enum blackOrWhite { black, white};


really what you''re suggesting is a situation where some value which is important to your class Foo, is also being important to people calling class Bar. This is slightly dubious.

However you can refer to the enumeration as Foo::BOOL

ie
void Bar::Fun(Foo::BOOL val)

as I say this is dubious as it couples callers of Bar with the Foo class, which might be quite inappropriate.

Obviously this isn''t a real example but you could translate an enumeration defined for Bar into the correct one for calls to Foo, so have some mapping.

Or have the enumeration defined for Bar and then Foo uses Bar''s enumeration, so the callers of Bar are using the Bar enumeration and don''t have to worry about knowing about Foo.

There are other things you can do to prevent the coupling but they will depend on the real situation and not some fabricated example. It is possible that the design is just altogther wrong (c:
JD
JD
Guys thanks for your suggestion however it won''t work. Here''s the code in entirety. Uncomment the code and take out ''int'' type and you''ll see it won''t compile because then you have to include foo.h header that will cause dependancy hell. Forward declarations don''w work on non reference/pointer types or enums. Would love to keep from xforming enums into ints. I''ll think about the design and see if I can eliminate cross coupling like pete mentioned.


  
// Foo.h: interface for the Foo class.

//

//////////////////////////////////////////////////////////////////////


#if !defined(AFX_FOO_H__FDDC8F46_20A2_11D7_9E6F_B353A79E2C18__INCLUDED_)
#define AFX_FOO_H__FDDC8F46_20A2_11D7_9E6F_B353A79E2C18__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


#include "Bar.h"

class Foo
{
public:
enum BOOL{FALSE, TRUE};

Bar bar;
};

#endif // !defined(AFX_FOO_H__FDDC8F46_20A2_11D7_9E6F_B353A79E2C18__INCLUDED_)


--------------------------------------------------------------

// Bar.h: interface for the Bar class.

//

//////////////////////////////////////////////////////////////////////


#if !defined(AFX_BAR_H__FDDC8F47_20A2_11D7_9E6F_B353A79E2C18__INCLUDED_)
#define AFX_BAR_H__FDDC8F47_20A2_11D7_9E6F_B353A79E2C18__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


//#include "Foo.h"


class Bar
{
public:
void Fun(int /*Foo::BOOL*/ boolval);

};

#endif // !defined(AFX_BAR_H__FDDC8F47_20A2_11D7_9E6F_B353A79E2C18__INCLUDED_)

---------------------------------------------------------------
// Bar.cpp: implementation of the Bar class.
//
//////////////////////////////////////////////////////////////////////
#include "Bar.h"
#include <iostream>
using namespace std;

void Bar::Fun(int/*Foo::BOOL*/
boolval)
{
cout << boolval << endl;
}
---------------------------------------------------------------

// zzz.cpp : Defines the entry point for the console application.

//

#include "Bar.h"
#include "Foo.h"

int main(int argc, char* argv[])
{
Bar bar;
bar.Fun(Foo::TRUE);

return 0;
}


Qw3r7yU10p!
Qw3r7yU10p!
if you only want to use a boolean then use the bool keyword
JD
JD
Pete, I used BOOL as an example I should have used enum FRUIT{APPLE, ORANGE}; as a better examle to avoid confusion. I was hoping you guys would know a trick to circumvent circular dependancy issue but I guess that''s impossible. Enums are not problematic under normal circumstances it''s only when you write code like I''ve done above ie. special case, is when things get iffy. I''ll just have to live with some of my vars being ints instead enum types and my function decl. using ints as well. Okey dokey then. Thanks for your input guys
Qw3r7yU10p!
Qw3r7yU10p!
AP: You've missed the point - the function in Bar depends on the enumeration in Foo. So you can't just use a forward declaration as Bar needs to know explicitly about Foo's BOOL.

JD: Enumerations are prime candidates for growing into polymorphic classes or converting to a strategy pattern. Even If you didn't do this, it looks as though your design is saying 'I have some value which is used by both Foo and Bar to determine conditional behaviour'. It may be best to move that into a separate class (rather than just a global enumeration).

class Fruit
{
Type type_;
public:
enum Type{apple, orange};
Fruit(const Type&);
Type type() const;
};

You pass the Fruit to the function rather than the enumeration.

void Sheep::Eat(const Fruit&);
...
Sheep baa;
baa.Eat(Fruit(apple));

you'll start switching on the type of the fruit which suggests moving to polymorphic classes. The fruit hierarchy will grow then to incorporate variations in behaviour and you'll no longer use the enumeration but the Apple, Orange, Satsuma classes instead. Code which varies with type will be localised within appropriate classes and everyone will think it's marvellous.

The refactoring website has a list which includes replace condtional with polymorphism.

[edited by - petewood on January 7, 2003 9:28:42 AM]
JD
JD
Pete, that''s one funny sheep example Your idea sounds interesting but I think it''s little overkill for me. I use enums as simple flags or state vars. For example, to record what csg operation the object underwent, etc. Originaly I had global enum types header but I felt it better to put enums within classes they were part of. Thanks for the links.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.