Note that there are some explanatory texts on larger screens.

plurals
  1. POC++ - Identifying a family of polymorphic classes without introducing tight coupling
    primarykey
    data
    text
    <p>Suppose I have an abstract base class called Component, which is the root of a hierarchy of GUI components. In such a case, we might have two subclasses, Button and Label, both of which are also abstract classes and exist as the root of their own respective hierarchies of concrete classes.</p> <p>Concrete classes inheriting from Button might include RoundButton and SquareButton. </p> <p>Concrete classes inheriting from Label might include TextLabel and PictureLabel.</p> <p>Finally, let's say there's an aggregate Container class that holds a collection of Component objects.</p> <p>The problem is that I have pointers to Component objects, but I need to identify them as being either Buttons or Labels. For example, if I want to specify that all Buttons should have a larger font for their interior text, I could iterate over all of the Component objects in the Container and somehow determine which ones are buttons, and call some method specific to buttons.</p> <p>One way for these Component "families" to identify themselves is with strings.</p> <pre><code>class Component { public: virtual char const * const getFamilyID() const = 0; }; // In Button.h char const * const COMPONENT_BUTTON = "button"; class Button : public Component { public: virtual char const * const getFamilyID() const { return COMPONENT_BUTTON; }; }; // Code sample if (strcmp(component-&gt;getFamilyID(),COMPONENT_BUTTON) == 0) // It's a button! </code></pre> <p>This is loosly coupled in that Component leaves the task of defining these families to its children; it does not require knowledge of what families exist. The client needs to be aware of the different Component families, but if it's trying to target a specific one for some operation, then that can't be avoided.</p> <p>However, suppose we have really high performance requirements and we want to avoid comparing strings. It would also be nice to avoid making this function virtual so we can inline it. Also, if every subclass of Component is going to need to declare a global constant, it might be nice to somehow modify the Component class to either make this a requirement or make it unnecessary.</p> <p>One solution to this problem is to define an enumerator in Component.h </p> <pre><code>enum COMPONENT_FAMILY { COMPONENT_BUTTON = 0, COMPONENT_LABEL, // etc... }; </code></pre> <p>In this case getFamilyID() can just return a COMPONENT_FAMILY enum and we can basically just compare ints. Unfortunately, this means that any new component families will have to be "registered" in this enum, which is easy but isn't entirely intuitive for other programmers. Also, the method still has to be virtual unless we make a nonstatic COMPONENT_FAMILY member that we know will have extremely low cardinality (not ideal).</p> <p>What would be a good way to solve this problem? In my case, performance is key, and while something similar to the enum solution seems easy enough, I'm left wondering if I'm overlooking a better way.</p> <p>--- EDIT ---<br> I realize that I should probably point out that in the actual system, the Container equivalent can only store 1 Component from each family. Therefore, the Components are actually stored in a map such as:</p> <pre><code>std:map&lt;COMPONENT_FAMILY, Component*&gt; </code></pre> <p>Applied to my simple example here, this would mean that a Container could only contain 1 Button, 1 Label, etc.</p> <p>This makes it really easy to check for the existence of a particular type of Component (log time). Therefore, this question is more about how to represent COMPONENT_FAMILY, and how to determine the Component's type when I'm adding it to the map.</p> <p>In other words, a component's sole purpose is to be identified as a specific piece of functionality added to the Container, and together all of the components define a specific behavior for the container.</p> <p>So, I don't need to know the type of a Component, that's already implied. I am specifically asking the Container for a specific type of Component. What I need is a way for the Component to communicate its type so it can be mapped in the first place.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. COYou say "Unfortunately, this means that any new component families will have to be "registered" in this enum, which is easy but isn't entirely intuitive for other programmers" ... why? You can publish the enum in an API and also have a delimiter enum member `COMPONENT_END` which allows the clients to decide if they are out of the enum bounds. As long as you maintain backwards compatibility by only adding new members directly before the delimiter value, changes should be transparent to the client. Enums also have symbolic names for debugging, and can be defined in a header file.
      singulars
    2. COYou're worried about speed for iterating over a bunch of GUI components in order to manipulate their fonts? That seems wrong. Could you possibly be slower than the font engine that has then to change all those fonts? or, FTM, the users, which have only their human eyes for following these update?
      singulars
    3. CO@sbi: This is, as my examples usually are, a simple example that captures the essence of the problem without providing too many unnecessary details. This actual system iterate over the components in containers, calling different functions for all of them, tens to hundreds of thousands of times per second.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload