-2

I want to keep my code modular. At the moment I have my code set-up to pass functions from a child class to a parent class. However it does not compile at all. Now I want to get rid of the passing functions all together but keep the 'modular-ness'.

Updates: I added more information about what my code is doing. I still left out majority of what I am doing. Class Molecule is optimizing multiple instances of Class Rates. Class Rates is optimizing multiple values that are generated by a single function inside Rates.

Class Data_Analysis {
    virtual double find_rms_A (vector<double>) = 0;
    virtual double find_rms_B (vector<double>) = 0;
    virtual double find_rms_C (vector<double>) = 0;
    double E (double (Data_Analysis::*fxn(vector<double>)) {
        // doing tons of stuff
        (this->*fxn)(vec);
        //Simplex is third party library that requires a function that 
        // takes vector<double> and outputs a double
        //http://www.codeguru.com/cpp/article.php/c17505/Simplex-Optimization-Algorithm-and-Implemetation-in-C-Programming.htm
        Simplex((this->*fxn)(vec)); 
    }
};

Class Molecule: Data_Analysis {
    virtual double find_rms_A (vector<double> ) {
        // using variables only declared in Molecule
        double rms = 0.0
        for ( int data_point_A = 0; data_point_A < num_data_point_A; data_point_A++) {
            Rates r(data_point_A);
            r.run_simulation_v1();
            rms += r.return_rate();
        }
        return rms;
    }

    virtual double find_rms_B (vector<double>) {
        // using variables only declared in Molecule
        double rms = 0.0
        for ( int data_point_B = 0; data_point_B < num_data_point_B; data_point_B++) {
            //do stuff
            rms += rate;
        }
        return rms;
    }
    void optimize_A () {
        // set variables for type of optimization A
        E(&Data_Analysis::find_rms_A);
    }
    void optimize_B () {
        // // set variables for type of optimization B
        E(&Data_Analysis::find_rms_B);
    }
};

Class Rates: Data_Analysis {
    virtual double find_rms_C (vector<double>) {
        // using variables only declared in Rates
        double rms = 0.0
        for ( int data_point_C = 0; data_point_C < num_data_point_C; data_point_C++) {
            // run simulation that is completely different than anything used in Molecule
            rms += rate;
        }
        return rms;
    }
    void optimize_C () {
        // set variables for type of optimization C
        E(&Data_Analysis::find_rms_C);
    }
};

Things I have tried to make passing functions work:

Virtual Function 1, Virtual Function 2, Virtual Function 3: "cannot declare variable ‘r’ to be of abstract type ‘Child2’"

Pointer Functions 1, Pointer Functions 2: "cannot convert ‘double (Child1::)(std::vector)’ to ‘Parent::fxn {aka double ()(std::vector)}’ in initialization" (The asterisks are making things italics.)

So, I want to re-organize my code to get around passing functions. But I have no idea how to do this without getting rid of 'function E' and repeating the code in functions A-D (aka destroying the modular-ness). Any tips/advice?

Community
  • 1
  • 1
S. J.
  • 11
  • 3
  • 1
    Post some real code that illustrates what you are talking about. –  Feb 24 '17 at 17:50
  • 1
    Could you please elaborate on the actual use case you're trying to implement. Because your example looks too contrived. – rustyx Feb 24 '17 at 17:59
  • This sounds like an XY problem. What are you trying to actually achieve with that weirdness? – Rob K Feb 24 '17 at 18:53
  • I have added more directed code. Hopefully this helps. I didn't want to post my full code since I didn't think most of it is relevant. – S. J. Feb 24 '17 at 19:49

2 Answers2

0

If you are going to pass a function specific to a child, don't do it through virtual functions defined in Parent. Kill the virtual functions, and pass the child-specific functions you want directly into E. Use std::bind to wrap the Child1 or Child2-ness, so that E doesn't care about the function other than its arguments.

class Parent {
    double E (std::function<double (vector<double>)> fn) {
        // doing tons of stuff
        fn(vec);
    }
};

class Child1: public Parent {
    double A (vector<double>) {
        // using variables only declared in Child1
    }
    double B (vector<double>) {
        // using variables only declared in Child1
    }
    void F () {
        E(std::bind(&Child1::A, this, std::placeholders::_1));
        E(std::bind(&Child1::B, this, std::placeholders::_1));
    }
};

A design litmus test is: If it doesn't make sense to implement a virtual function in all of the child classes, it probably shouldn't be one...

You could also use a lambda for the call instead.

Also, are you sure you want to be passing a vector by value? You probably want to pass by const reference instead.

Peter
  • 14,559
  • 35
  • 55
0

At least at first glance, it seems like your problem is arising from the code not being modular enough.

It looks to me like you're combining what are really two separate things into a single class. You have something to carry out some sort of overall computation, and something to carry out individual computations that it uses.

This seems to me like a situation where you want something more along these general lines:

// Each derived object only (apparently) needs two functions, so that's
// what we'll define as the interface:
struct base { 
    // equivalent to child1::A and B, and to child2::C and D:
    virtual double A(std::vector<double> const &) = 0;
    virtual double B(std::vector<double> const &) = 0;
};

// Then a class for the overall computation, using (a pointer to) one of the 
// preceding:    
struct compute {
    // equivalent to Parent::E().
    double E (base *b) {
        b->A(vec);
        Simplex(b->A(vec));
        b->B(vec);
        Simplex(b->B(vec));
    }    
};

struct child1 : public base {
    // Now each child provides two functions:
    double A(std::vector<double> const &p) { 
        // do child1 computation A
    }
    double B(std::vector<double> const &p) {
        // do child1 computation B
    }

    void F(compute *c) { 
        c->E(this);
    }        
};

struct child2 : public base {
    double A(std::vector<double> const &p) { 
        // do child2 computation A
    }
    double B(std::vector<double> const &p) {
        // do child2 computation B
    }
    void G(compute *c) { 
        c->E(this);
    }    
};

Arguably, child1::F() and child2::G() should probably really be a single function in the base class, since they both do essentially the same things.

If you might have a collection of pointers to either child1 or child2 objects (so you don't know until run-time whether a particular pointer will refer to a child1 or a child2), and you want to carry out the same operations on all of them, the preceding design makes sense.

On the other hand, if you know at compile time whether a particular instance will be a child1 or a child2, you could pass the child1 or child2 as a template parameter, avoiding the overhead of a virtual function:

// The class contained only a single function, so it can be just a function:
template <class F>
double compute(F const &f) {
    f.A(vec);
    Simplex(f.A(vec));
    f.B(vec);
    Simplex(f.B(vec));
}

class child1 { // no longer needs a common base class
    double A(std::vector<double> const &);
    double B(std::vector<double> const &);
    void F() { compute(this); }
};

class child2 { // no longer needs a common base class
    double A(std::vector<double> const &);
    double B(std::vector<double> const &);
    void G() { compute(this); } 
};
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I updated my question. I have not read through everything you are doing, but I think my update conflicts with your solution. – S. J. Feb 24 '17 at 19:50