Polymorphic uninvolved parenting?

Started by
9 comments, last by LorenzoGatti 8 years ago

My goal is to have a base class that deals with all the stuff that the Derived ones will have in common, but then allows each of the derived classes to implement their specific stuff on their own, without the Base knowing or caring about any of it, and still somehow be used in a polymorphic pointer. The derived classes are supposed to have distinct usefulness, so they'll have different functions altogether. One might deal with sprites, the other with text, etc, but, again, they do share some background/backstage functionalities.

Currently I'm declaring a pointer of type Base*, and defining it as type Derived*. And it works fine but only until I call one of Derived's specific functions. I get this error:


'class Base' has no member named 'function'.

I understand why that error occurs: I'm accessing a Derived through a Base pointer, and sure enough, Base knows nothing about that function because it was not declared in Base. That might be one solution, to declare it in Base, but that would then force me to also declare every other function specific to each derived class, in the Base class, and that's what I'd like to avoid.

Is there a way to achieve this?


Some (pseudo)code, illustrating what I'm doing and what I'd like to achieve (streamlined for simplicity, assume everything is public):
base.h


class Base
{
	virtual ~Base() =0;
	virtual void funk() =0;

	void common() {}		// deal with shared stuff

	// knows nothing about der1::draw() and der2::write()
};

der1.h


class Der1 : public Base
{
	void funk() { ... }
	
	void draw();		// specific to this class
};

der2.h


class Der2 : public Base
{
	void funk() { ... }

	void write(); 		// specific to this class
};

elsewhere.h


Base* ptr1;
Base* ptr2;

elsewhere.cpp - this is my actual goal


ptr1 = new Der1();
ptr2 = new Der2();

ptr1->draw();
ptr2->write();

I created a pointer of type Toilet so I don't have to go to the bathroom as often.

Advertisement
You can do this with dynamic_cast, but is there some reason you must access the derived classes only through pointers to their base class? Usually this kind of thing is a design smell - a pointer to a base class is supposed to mean that you don't care what the derived type is, only that it implements the same interface of the base class. If you know you're going to have a Der2, why not simply store one of those?

Either use a Derived* instead of Base* where necessary (part of the code might deal with a specific derived class, while another part is more generic and only needs base pointer), move it into the base class/interface, or come up with a messy system to ask (through a Base*) what the actual derived type is, and then cast to Derived* and then call the function (if you find yourself needing to do that a lot, theres probably some bigger architectural problem).

For example, if both "draw" and "write" actually just draw the thing, they should both be called just that (and not separate names for no reason), and you can then put it in the base class.

In some cases, you might find that some base class things are not used by all the derived classes. This can be fine if it allows more flexibility in what kind of derived classes you can create. But remember that increased flexibility often comes with reduced maintainability/readability/performance (compare having 1 god-class that does all the things, and a bunch of specialized classes, or having everything be a global variable vs keeping things nicely local and scoped)

o3o

Reading material. If you can afford it, go get copies if the books referenced at the bottom, used if you can find them.

If you decide to skip the articles and books, do not miss the summary:

Guideline #1: Prefer to make interfaces (aka: base class, ABC, ADT) nonvirtual.

Guideline #2: Prefer to make virtual functions private.

Guideline #3: Only if derived classes need to invoke base implementation of a virtual function, make that virtual function protected.

Guideline #4: A base class destructor is the exception, make it either public and virtual or protected and nonvirtual.

In games generally the game objects do not draw themselves. Game objects are containers. The containers have meshes, textures, effects, billboards, sprites, UI elements, light emitters, and other drawable elements, among others. Game objects are generally worked on as a tree. The tree is passed to a rendering system which traverses the tree, queries the container for objects affecting drawing, and figures out how to render them.

Just to make it clear, my intention is to create several parts of a UI, in which some parts deal with several lines of plain text, some are lists of information (several texts in each line), some show sprites, etc.

My intention is to have a class that manages the screen, storing each part in the same vector<> (or maybe map<>, not sure yet). My plan was to have that vector be vector<Base*> or something that would allow the managing class to easily access each part as needed, to pass on mouse/keyboard input, controlling focus/unfocus, selected/unselected, for drawing them in a for loop rather than risk forgetting some, etc, while each of them still knows how to display their own thing by themselves.

The functionality to draw a frame and background is common to them all, as are those I just mentioned above, but a list is going to have an addIndex() function, while a textBox won't. That addIndex() is as of now being called by the managing class (although, it just occurred to me that this might not be how I want it to be - perhaps the class should know when to add indexes by itself based on info from elsewhere, not by (arbitrary) request from the manager).

I created a pointer of type Toilet so I don't have to go to the bathroom as often.

Perhaps more of a flyweight pattern, then?

Many UI systems follow the flyweight pattern, some rather loosely, where all the UI elements are part of bigger container. The individual UI elements are just the minimal parts needed to be displayed.

If you've studied it, consider the windows Resource Definition files. Each entry has an optional name, an enumeration value of what control they are, and a small number of options or strings. Many are just two or three elements, some go up to six or so. From this collection of tiny resource statements a full GUI can be created.

The data structure is about as simple as the file format. A small structure that is easily manipulated, but that is universally shared among all programs. Programs can register to handle events related to the named elements in the data.

since you are implementing a UI system, all UI elements should simply have Draw()/Paint()/Render()/Display() function which each subclass implements; whether its plain text, sprites, or a container of other elements, there is no need to have a different function name when the intention is the same - in each case, you are just trying to display the element for the user.

Making these threads is useful for me to think about things, but it turns out this is leading me to a confusion about what I'm doing, but at the same helping me find the cause of the confusion. I made another thread before this one that also lead me to confusion (and I realize now it's not all that different from this one). It's no one else's fault but mine, really.

It think my confusion stems from the fact that I can't clearly visualize what I want while I'm not being able to prototype something. No matter how many drawing I make on paper. Perhaps I would benefit from explaining my actual goal in detail, and perhaps I could do it right here (hope it's ok). Maybe someone can tell me then if what I'm trying to do with the UI is overkill or not, or maybe if there's a better approach that I could take (considering I'm a beginner/intermediate programmer).

The project I'm trying to work on is intended to be essentially a resource management game, in a similar vein to the old Pizza Tycoon, but set in a medieval fantasy world where the player is an inn keeper. Aside from running the inn, the inn keeper can also trade/buy/sell information to travelers, adventurers, spies, etc (goblins robbing travelers in a road? The emperor planning to attack the northern towns?), and this is supposed to be one aspect in which the player could have an influence in the overall storyline (for example, there is a war, and if you trick a spy, you can potentially damage the enemy - or you could get murdered for it). The player can also hire spies and thieves for gathering more sensitive information, or even guards for protection, among others.

Since I found out I'm terrible at making sprite animations, I thought - for now at least - of leaving out the possibility to view the inside of the inn where one might contemplate the NPCs having a drink or eating a meal, and the view of the town, where one might see... something interesting and relevant that didn't cross my mind so far.

That leaves me with a game that is practically just a GUI, with a handful of buttons with which to alternate between each screen that, in turn, show the player information about his current patrons, the regular ones, allow him to study his acquaintances for potential strategies or just curiosity, check the stock/sales/recipes, the hired staff, the hired mercenaries/thieves/spies/etc, view all the money stuff, view character progression, etc. As of my current plans, the currently in-house costumers would be shown in a list (each with a small picture and a few icons to show their mood and other things, and also their known name, their current expenditure, if they rented any rooms, etc - just some quick info there) where the player could get into dialogues to make their acquaintance, but also get information about the outside world, and even see a sheet with the detailed (known) NPC information with hopefully a slightly bigger portrait.

I think I'm also divided between attempting to build a proper or a good-enough ui system, or attempting to customize each part of each screen as I go along and as I think of the stuff that could be shown there...

Here's a screenshot from my first attempt at this, somewhere in 2014, on windows console. There was no game content either, I just had managed to build the menu you see on the left. I was at that point going to attempt to build each of screens corresponding to a menu option. Hopefully it illustrates the amount of stuff I have planned to be able to display (some, like the Necrology and Animals options, aren't really in the plans, and I'm intending to streamline a lot of what's shown here).

w827Bww.jpg

I created a pointer of type Toilet so I don't have to go to the bathroom as often.


Since I found out I'm terrible at making sprite animations, I thought - for now at least - of leaving out the possibility to view the inside of the inn where one might contemplate the NPCs having a drink or eating a meal, and the view of the town, where one might see... something interesting and relevant that didn't cross my mind so far.

You could go the route of a text adventure game (plus GUI). Or if you can do pixel art but struggle with animation, maybe just don't make animations and have the game in first person POV (like in old school dungeon crawlers). NPCs (goblins, travelers, the emperor's spies, etc) can just appear in the player's view. Or if you can draw by hand, you can just scan a drawing of the player's static view (inside of the inn), some NPCs, clean them up a little bit, then render them together in a final scene. Back before I got a handle on pixel art (disclaimer: I still pretty much suck) I did this and it turned out somewhat okay looking.


Making these threads is useful for me to think about things, but it turns out this is leading me to a confusion about what I'm doing, but at the same helping me find the cause of the confusion. I made another thread before this one that also lead me to confusion (and I realize now it's not all that different from this one). It's no one else's fault but mine, really.

In this specific case, it seems like you're trying to implement an abstraction over all objects, without knowing how to do so.
You might want to read up on virtual functions, that's the simplest way in C++ to provide an abstraction as would be required by a UI.

a pointer to a base class is supposed to mean that you don't care what the derived type is

For example, if both "draw" and "write" actually just draw the thing, they should both be called just that (and not separate names for no reason)

In games generally the game objects do not draw themselves. (...) Game objects are generally worked on as a tree.

all UI elements should simply have Draw()/Paint()/Render()/Display() function which each subclass implements; whether its plain text, sprites, or a container of other elements, there is no need to have a different function name when the intention is the same - in each case, you are just trying to display the element for the user.

Good stuff to keep in mind. Thanks.

You could go the route of a text adventure game (plus GUI)

I am considering that. Perhaps I should just do it and get to work...

I created a pointer of type Toilet so I don't have to go to the bathroom as often.

This topic is closed to new replies.

Advertisement