简体   繁体   中英

c++ iterate over base and derived class

I'm trying to find a way to get an iterator to work on a list of custom objects and a list of objects derived from that custom object. My, perhaps misguided, goal is to allow me to leave the "production" code and objects intact yet accessible from the "experimental/extended" things that I'm trying out.

Here's a pretty minimal example of what I'm trying to do.

#include <iostream>
#include <list>
using std::cout;
using std::endl;
using std::cin;
using std::list;

struct comp{
    double x,y;

    void print(){
        cout << "x: " << x << endl;
        cout << "y: " << y << endl;
    }
    comp(){
        x = 0;
        y = 0;
    }
    comp(double X, double Y){
        x = X;
        y = Y;
    }
    // Standard/Tested Member Functions
};

struct base{
    list<comp> components;
    double known, tested, variables;

    void print_comps(){
        for (list<comp>::iterator it = components.begin(); it != components.end(); ++it){
            // Ideally, this function should work for comp1 and comp1x
            // as inherited in the basex class
            it->print();
        }
    }
    // Standard/Tested Member Functions
};

struct compx : comp{
    double w,z;
    double some, alter, nates;

    void print(){
        cout << "x: " << x << endl;
        cout << "y: " << y << endl;
        cout << "w: " << w << endl;
        cout << "z: " << z << endl;
    }
    compx(){
        x = 0;
        y = 0;
        z = 0;
        w = 0;
    }
    compx(double X, double Y, double Z, double W){
        x = X;
        y = Y;
        z = Z;
        w = W;
    }
    // Experimental/Un-tested Member Functions
};

struct basex : base{
    list<compx> components;
    double exper, imen, tal;

    // void print_comps(){} // This should be inherited from base

    // Experimental/Un-tested Member Functions
};

int main(){

    base compilation1;
    compilation1.components.push_back(comp(1,2));
    compilation1.components.push_back(comp(3,4));
    cout << "printing normal struct" << endl;
    compilation1.print_comps();

    cout << endl;

    basex compilation2;
    compilation2.components.push_back(compx(9, 5, 5, 6));
    compilation2.components.push_back(compx(7, 2, 1, 8));
    cout << "printing extended struct" << endl;
    compilation2.print_comps();     // Prints nothing

    cout << endl;

    cout << "Printing via specific iterator" << endl;
    for (list<compx>::iterator it = compilation2.components.begin(); it != compilation2.components.end(); ++it){
        it->print();    // Works as expected.
    }

    cout << endl << endl << "Press ENTER to exit." << endl; cin.get();
    return 0;
}

Ideally, I would be able to iterate over both the original class and the extended class in the same functions so I don't clutter the extended class with all the original code. This would allow me to simply move code from the extended class to the original class as those variables or functions are proven or matured.

Background:

  • I'm not married to lists -- any other iterable class would be fine.
  • I'm not a developer -- I'm a ChemE trying to make daily tasks a bit easier without breaking what I've already built.
  • Branches in a git repository are not a great solution because other non-developer, potentially code-challenged, folks may try to extend this. Getting them to use even one branch would be a miracle.
  • I'm using g++ 7.4.0 on Linux (Lubuntu) and 6.3.0 on Windows 7.

TL;DR:

Is there a way to get an iterator of list<parent_object> to also iterate over list<child_object> ?

This could be solved by having base as a template http://cpp.sh/7r2x6a

template<typename T>
struct base
{
    list<T> components;
    double known, tested, variables;

    void print_comps(){
        for (auto it = components.begin(); it != components.end(); ++it){
            // Ideally, this function should work for comp1 and comp1x
            // as inherited in the basex class
            it->print();
        }
    }
    // Standard/Tested Member Functions
};

If you're okay with not being able to mix comp and compx objects together in the same list , then you can use a templated function to avoid duplicate code.

For example, you can do the following in your struct base :

struct base{
   list<comp> components;
   double known, tested, variables;

   void print_comps() {print_comps_aux<comp>(components);}

   protected:
      template <typename CompType> void print_comps_aux(list<CompType> & compsArg)
      {
         for (typename list<CompType>::iterator it = compsArg.begin(); it != compsArg.end(); ++it){
            it->print();
         }
      }

   // Standard/Tested Member Functions
};

... and then in your struct basex you can just have this:

[...]

void print_comps() {print_comps_aux<compx>(components);}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM