• Advertisement
Sign in to follow this  

leave function definition "empty" (c++) ?

This topic is 1088 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi

 

I have a general class handling inventories in my game engine (c++)

It has a function getItemNames:

char * gameInventoryMaster::getItemName(gameItem * uu)
{
	if(useSpecialNames)
		return getSpecialItemName(uu);
	else
		return IDATA[uu->type].name;
}

The getSpecialItemName is just declared in the general engine class, not defined.

Instead it is defined in each game separately (because some games may have diablo-like item modifiers that affect name, while others affect item names in another manner etc).

 

Problem is its unpractical to be forced to define that function in all games using the engine (some games dont use inventories or at least not specialItemNames).

 

If i dont add a definition i get compiler errors (fatal error LNK1120: 1 unresolved externals). I want to leave it "empty" (not there) if i dont use it. Is it not possible in c++?

 

Thanks
Erik

Share this post


Link to post
Share on other sites
Advertisement
What do you want to happen if somebody calls this `"empty" (not there)' function?

Also, you probably should be using std::string instead of raw pointers to char. The ownership issues with returning pointers to char are a nightmare. And getItemName should probably be a const member of gameInventoryMaster and take a const pointer to gameItem, since I don't expect it to make changes to either of those things.

Share this post


Link to post
Share on other sites

Im fine with crashing if calling an "not there" function. Its either used or not used for an entire project so its not gonna be a problem.

Or returning the string "NO NAME" if its possible to define a default function should there not be anyone defined.

Share this post


Link to post
Share on other sites

I presume this function is declared virtual?  If so, what you need is a pure virtual declaration (use " = 0" after the declaration), and no definition:

class Base
{
    virtual void FunctionThatIsEmptyInBase() = 0; //will fail without = 0, since it isn't defined anywhere
};

class Derived : public Base
{
    virtual void FunctionThatIsEmptyInBase(); //add the override keyword before the semicolon if using C++11 or later
};

void Derived::FunctionThatIsEmptyInBase()
{
}

A pure virtual function marks the entire class as pure virtual, which means it can never be instantiated.  Any class that derives from a pure virtual base class must provide implementations for all pure virtual functions, or else it too cannot be instantiated, and must be further derived with remaining pure virtual functions implemented someone down the chain.

Share this post


Link to post
Share on other sites
Given more context, there might be a more graceful solution, but as it stands it sounds as though you are just annoyed that the engine begs you to fill in a blank every time you inherit from a certain class.

In that case, create a single class that fills in all those blanks (the names, etc.) and instead of later deriving from the original class, derive from your new class.


L. Spiro

Share this post


Link to post
Share on other sites

I agree that the broader strokes of this design smell funny, I would encourage OP to consider a different line.

 

But, ignoring that for now and dealing with the problem at hand, I think what'd I'd do is make getSpecialItemName a function pointer, and set it to a default implementation. For a game to override this function, what they would do is create their own function with a compatible signature, and then set the getSpecialItemName function pointer to point to their function. This is basically implementing one-off virtual inheritence, though, and if you're implementing this all in C++ (but looks like you're using C, maybe?) you'd be better off just using the facilities provided by the language.

 

If you take this approach, do provide a default function, even if what it does is force the program to exit with an error code (because its an error for the client to call getItemName with an ID that invokes getSpecialItemName when it has not been provided). You could say "If the function pointer is null, then skip it." but then A) you'd have to check at every call site, and B) what would you then return anyways? To be clear, there's nothing preventing client code from setting the function pointer to null, so this doesn't prevent that error, but giving it a non-null default makes later assigning it one an explicit error.

Share this post


Link to post
Share on other sites
Ravyne, the title of the thread says he is using C++, and I don't think the :: in the code means anything in C.

Share this post


Link to post
Share on other sites

The need for adding dummy methods is a clear sign of a bad OO design. If a method is not useful in any and all of the derived classes then it should not be in the base class.

Therefore you would be better off correcting this design blunder by deleting it from your "engine" class.

You should also consider not using inheritance as much. Often its simpler to use composition and have complete objects owned and called by some class in your game than to derive from some class and then be forced to find and fill all those gaps.

Share this post


Link to post
Share on other sites

A better design here would be to make getItemName virtual, with " return IDATA[uu->type].name;" as the default implementation. When a special item name is needed, the user would override this method. 

Share this post


Link to post
Share on other sites


I presume this function is declared virtual?  If so, what you need is a pure virtual declaration (use " = 0" after the declaration), and no definition:

 

Why does everyone think the OP is using a virtual function?

 

He says that the function is left undefined. It's not a pattern that I like, but approaching this as if inheritance is already being used and then using this assumption to criticize the OP's poor use of inheritance doesn't make any sense.

 

I have to ask, where does that useSpecialNames bool is the sample code come from? What sets that? Wherever that bool is set, you might be able to just pass in a whole inventory object, or maybe an inventory object factory, to the game instead of the bool.

 

So now I'll make my assumptions:

 

I believe the OP's engine is structured in such a way that the inventory object is constructed deep within "engine" code and so inheriting from it and overriding functions is not an easy option to add: at least it wasn't as easy as this undefined function so that's what happened. I suggest, if undefined functions implemented for specific games is the only practical solution available right now, you should write up an inventory interface and replace the constructor for the inventory class with something that returns a pointer to this interface. Games that have no inventory could just return null, so only a minimal amount of boilerplate is necessary. Games that can use the default inventory can construct the existing class and return it. Games with a custom inventory can inherit from the base object for small differences or just reimplement the whole class for drastic changes.

 

In my opinion, I prefer an "engine" to be a collection of useful classes that can be put together into a game on the game side, so the choice of which inventory class to use or whether to even use one is squarely on the game side, not the engine side. Each game might require a little more glue code this way but it's much more flexible.

Share this post


Link to post
Share on other sites

Ravyne, the title of the thread says he is using C++, and I don't think the :: in the code means anything in C.

Bah, you're right. I read neither title or code carefully -- just assumed the Cish approach OP was already winding down implied C.

 

Using C++ properly, I'd define an interface with the base-case of non-special names implemented, and allow the client code to override with an implementation that first traps special item IDs and respond appropriately, or call into the base implementation to handle normal ones.

 

or another relevant approach would be the decorator pattern, if there's a chance for client code to intervene between getting the name and rendering.

Edited by Ravyne

Share this post


Link to post
Share on other sites

Considering this involves gameplay data I would be careful in using code constructs to do this. What about something along the lines of:

typedef std::map<gameItem*, std::string> SpecialNamePool;
// ^ one of those created somewhere, populated at runtime with data, possibly dynamically updated

...

char * gameInventoryMaster::getItemName(gameItem * uu)
{
    // assume SpecialNamePool *namePool = some persistent object, also std::reference_wrapper will do
    if(this->namePool) {
        auto spec(namePool->find(uu));
        if(spec != namePool->cend()) return spec->second.c_str(); //<-- ok, don't do that. Really. Not even valid code. Maybe return std::string
    }
    return IDATA[uu->type].name;
}

Note this buys considerably more flexibility than you probably need and in some cases isn't even viable but this is a data-oriented problem and should be solved with data IMHO.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement