Search code examples
c++pointersvirtual

Is there any way to avoid declaring virtual methods when storing (children) pointers?


I have run into an annoying problem lately, and I am not satisfied with my own workaround: I have a program that maintains a vector of pointers to a base class, and I am storing there all kind of children object-pointers. Now, each child class has methods of their own, and the main program may or not may call these methods, depending on the type of object (note though that they all heavily use common methods of the base class, so this justify inheritance).

I have found useful to have an "object identifier" to check the class type (and then either call the method or not), which is already not very beautiful, but this is not the main inconvenience. The main inconvenience is that, if I want to actually be able to call a derived class method using the base class pointer (or even just store the pointer in the pointer array), then one need to declare the derived methods as virtual in the base class.

Make sense from the C++ coding point of view.. but this is not practical in my case (from the development point of view), because I am planning to create many different children classes in different files, perhaps made by different people, and I don't want to tweak/maintain the base class each time, to add virtual methods!

How to do this? Essentially, what I am asking (I guess) is how to implement something like Objective-C NSArrays - if you send a message to an object that does not implement the method, well, nothing happens.

regards


Solution

  • Instead of this:

    // variant A: declare everything in the base class
    void DoStuff_A(Base* b) {
      if (b->TypeId() == DERIVED_1) 
          b->DoDerived1Stuff();
      else if if (b->TypeId() == DERIVED_2) 
          b->DoDerived12Stuff();
    }
    

    or this:

    // variant B: declare nothing in the base class
    void DoStuff_B(Base* b) {
      if (b->TypeId() == DERIVED_1) 
          (dynamic_cast<Derived1*>(b))->DoDerived1Stuff();
      else if if (b->TypeId() == DERIVED_2) 
          (dynamic_cast<Derived2*>(b))->DoDerived12Stuff();
    }
    

    do this:

    // variant C: declare the right thing in the base class
    b->DoStuff();
    

    Note there's a single virtual function in the base per stuff that has to be done.

    If you find yourself in a situation where you are more comfortable with variants A or B then with variant C, stop and rethink your design. You are coupling components too tightly and in the end it will backfire.

    I am planning to create many different children classes in different files, perhaps made by different people, and I don't want to tweak/maintain the base class each time, to add virtual methods!

    You are OK with tweaking DoStuff each time a derived class is added, but tweaking Base is a no-no. May I ask why?

    If your design does not fit in either A, B or C pattern, show what you have, for clairvoyance is a rare feat these days.