1

I'm designing a software for displaying ModelView objects based on a DataModel.

The DataModel is displayed by a ModelView object which can itself contain a bunch of ViewObjects. It is like a container of ViewObjects to constitute to a ModelView and finally display the DataModel.

These ViewObjects can be dependent of each other inside the ModelView so for instance a position of one ViewObject may depend on another.

Then also the layout of the final screen is decided based on all of the ModelViews.

These ViewObject is inherited from a common BaseView class, but the client can simply add new ViewObject types to the hierarchy by inheriting from BaseView class. These derived classes may have specific functions to them which may need to be called in order to connect them together inside a ModelView.

Could you someone give me an idea how to do this without dynamic casting?

EDIT: I have defined the following class:

class EventView // ModelView class containing
{
private:
    //Pointer to BaseViews constituting to ModelView
    std::shared_ptr<BaseView> m_FlowView;   
    std::shared_ptr<BaseView> m_SourceView;
    std::shared_ptr<BaseView> m_TargetView;
    std::shared_ptr<BaseView> m_WorkerView;
    std::shared_ptr<TEvent> m_Model;
}

The client can inherit from BaseView a BaseView can be a line or a circle or a curve or anything else. Hence they can be totally different. In my point of view I need only just a list of BaseView objects to draw them but it is the responsability of the client code to interconnect them together and place them together. But as I will store only BaseView pointers client may need downcasting to interconnect the elements.

Minee
  • 408
  • 5
  • 12
  • Why would you want to avoid dynamic casting in this case? As per my experience, we did exactly that in one of our projects. _(But then again, maybe we did not do the smartest thing.)_ – Duck Dodgers Jan 17 '19 at 15:13
  • @JoeyMallone I would like to avoid it because the type of ViewObject is not bounded as client code can add new ones. – Minee Jan 17 '19 at 15:16
  • 1
    @JoeyMallone FWIW, `dynamic_cast` in code normally indicates a design flaw. There are time where it is the solution but like `goto` it is frowned upon. – NathanOliver Jan 17 '19 at 15:20
  • It's not clear why you think you need `dynamic_cast` in the first place. What is it your view wants to do with your `ViewObject` that it can't do via the `BaseView` interface? Can you add it reasonably to `BaseView`? If not, it means you seem to be trying to do something unique with your `ViewObject` that other `BaseView` can't support and `dynamic_cast` may be the solution. But it also means that your design may have flaws. Why should the client's view objects be "weaker" than yours? You are asking how to improve your design but we have no clue about the actual problem you your current design – François Andrieux Jan 17 '19 at 15:22
  • @NathanOliver, but what if I am passing an object of a derived class to a function as an argument. The function though accepts only as a parameter a pointer to a base class. Inside the function, I have to use then `dynamic_cast` on the pointer to base class, or not? – Duck Dodgers Jan 17 '19 at 15:22
  • @JoeyMallone If your function requires the derived type, it should make it's argument type the derived type. If it doesn't require the derived type then there is no reason to `dynamic_cast`. – François Andrieux Jan 17 '19 at 15:23
  • @JoeyMallone No. upcats are implicit `void foo(base*) {} foo(derived_ptr);` works without an explicit cast. – NathanOliver Jan 17 '19 at 15:24
  • @FrançoisAndrieux, my function requires one of the 15~16 derived types. so I wrote a base class and derived those 15~16 classes from that base class. – Duck Dodgers Jan 17 '19 at 15:25
  • @NathanOliver, yes, but inside the function, I cannot use the `base*` as if it were one of the derived types. I have to cast it. I mean, if `derived_ptr` had a member method `getParam1()`, I couldn't just do `base->getParam1()` inside the function. Ok, I should probably test that and not hijack the OP's post here. :) – Duck Dodgers Jan 17 '19 at 15:27
  • @JoeyMallone Ah yes, that is correct. Then you would need to cast. Normally though the base class would provide the interface and the derived classes to implement it. If they need to extend the interface then you do need to cast and a visitor pattern approach normally works. – NathanOliver Jan 17 '19 at 15:29
  • 4
    @JoeyMallone You may want to read [this](https://stackoverflow.com/questions/18439380/why-is-dynamic-cast-evil-or-not-should-i-use-dynamic-cast-in-this-case), [this](https://stackoverflow.com/questions/43307674/is-it-bad-design-to-use-dynamic-cast-in-c/43308504) and [this](https://softwareengineering.stackexchange.com/questions/363410/proper-design-to-avoid-the-use-of-dynamic-cast). If you need `dynamic_cast` to differentiate between 15 or 16 derived types from a base pointer you are almost certainly using polymorphism incorrectly and adding a lot of extra work for yourself. – François Andrieux Jan 17 '19 at 15:30
  • @FrançoisAndrieux, thanks. I check them right away. At OP, sorry about hijacking your post. Back to your question ... – Duck Dodgers Jan 17 '19 at 15:32
  • @FrançoisAndrieux Please see my edits – Minee Jan 17 '19 at 15:35
  • 2
    @Minee It seems it's up to the view object's implementer to manage the interconnections so you should never have to worry about casting. And when implementing those, it's not clear each view type couldn't receive it's related or component view objects with the concrete types. I just don't see where you are considering using `dynamic_cast` or (by extension) what rational you would have for doing so. So it's not really feasible to advise you on avoiding it's use, I would first need to understand where, how or why you would intend to use it in the first place. Maybe showing a [mcve] could help. – François Andrieux Jan 17 '19 at 15:38
  • @FrançoisAndrieux Actually yes you are right, I should never have to wory about how the elements should be interconnected. I guess my issue is come from the fact that when the client instantiate a ModelView with its ViewObject. I is not possible to decide about the position of the ViewObjects. Because the position also depends on the Layout of the screen. So once a layout is decided one can decide the position of ViewObjects. Hence, the client, not me, is obliged to do downcasting to set up each position of his objects after the layout is defined. I think the layout must be decided first then! – Minee Jan 17 '19 at 16:10
  • 2
    Modern GUI frameworks need to solve similar tasks - the way these coped with might serve as orientation for your problem. – Aconcagua Jan 17 '19 at 16:38
  • 2
    Question is a bit vague, but in general: You avoid casting by doing things the other way around: The creator of an object knows the exact type, and object itself knows the exact type. Anything which needs the type will needs to be done/called/created by these. Anything which has only the base class pointer shall only use the base class API. – hyde Jan 17 '19 at 21:08

1 Answers1

1

From what I understand from your question, you are storing base pointers of objects but from outside, you want to operate on them as the derived objects that they are.

Downcasting is essential in this case.

While your question is vague, I see your situation being very similar to a control in a dialog where both are windows but say a CheckBox is specialized window that you want to operate on specifically which has extended functions.

Major framework use casting for this problem like MFC here.

The newer Qt framework also use casting as in findChildren function.

I hope you can evaluate your solution given this info and maybe make peace with it.

zar
  • 11,361
  • 14
  • 96
  • 178
  • A note about Qt: normally you don't use or need casts. When you do seem to need them, most of the time it's a sign you could do things better. Even `findChildren` is a template method, which gives you pointer of desired type, no casting needed! Or what do you mean? – hyde Jan 17 '19 at 20:59
  • @hyde Right in Qt, usually you have the object declared and access it through it but if we stretch it to match to this post, we can see it being somewhat similar to findChildren (at least one way). It's template method but the point is we still have to provide the class type and id of the control. That said, we don't really know how the objects are being accessing in this question but I assume it's not direct otherwise typecasting will not be needed. – zar Jan 17 '19 at 22:34
  • @zar thank you for your help, I accept it is as an aswer as it helped be in general and also mentionning Qt gave me some ideas and references. Actually, you are right, the code I'm writing does not need to know about the specific type but if the user want to manipulate it specifically downcasting is necessary. – Minee Jan 26 '19 at 19:20