0

The code below does not produce what I want.

#include <iostream>
#include <vector>
#include <cstdlib>

using namespace std;

template<typename T> class Parent;
template<typename T> class Child1;
template<typename T> class Child2;

template<typename T> T fcn_default(const Parent<T> &obj, const T &phit){
    return 3.2 + phit;
}
template<typename T> T fcn_mod1   (const Child1<T> &obj, const T &phit){
    return 1.2 + phit;
}
template<typename T> T fcn_mod2   (const Child2<T> &obj, const T &phit){
    return 2.2 + phit;
}

template<typename T> class Parent{
    public:
        Parent() {
            fcn_ptr = &fcn_default;
        }
        T do_something(const T &phit){
            return this->fcn_ptr(*this, phit);
        }
        T (*fcn_ptr)(const Parent &, const T &);

};

template<typename T> class Child1 : public Parent<T>{
    public:
        Child1() {
        }
        T (*fcn_ptr)(const Child1 &, const T &);

};

template<typename T> class Child2 : public Parent<T>{
    public:
        Child2() {
        }
        T (*fcn_ptr)(const Child2 &, const T &);

};

typedef double lrtType;

int main(){
    std::vector< Parent<lrtType> * > objects;

    Child1<lrtType> *test11 = new Child1<lrtType>();
    objects.push_back(test11);

    Child1<lrtType> *test12 = new Child1<lrtType>();
    test12->fcn_ptr = &fcn_mod1;
    objects.push_back(test12);

    Child2<lrtType> *test2 = new Child2<lrtType>();
    test2->fcn_ptr = &fcn_mod2;
    objects.push_back(test2);

for (size_t i = 0; i < objects.size(); ++i) {
        std::cout << objects[i]->do_something(2) << std::endl;
}

    cout << "test" << endl;
}

It produces:

5.2
5.2
5.2
test

And I was expecting:

5.2
3.2
4.2
test

My understanding is that the vector objects is of type Parent and therefore calls its own methods and not the children's ones.

I have nearly cracked it using "Curiously recurring template pattern" but I have a last problem during the initialization of the vector objects.

#include <iostream>
#include <vector>
#include <cstdlib>

using namespace std;

template<class Child, typename T> class Parent;
template<typename T> class Child1;
template<typename T> class Child2;

template<typename T> T fcn_mod1   (const Child1<T> &obj, const T &phit){
    return 1.2 + phit;
}
template<typename T> T fcn_mod2   (const Child2<T> &obj, const T &phit){
    return 2.2 + phit;
}

template<class Child, typename T> class Parent{
    public:
        Parent() {
            fcn_ptr = &Parent::fcn_default;
        }
        T do_something(const T &phit){
            return static_cast<Child*>(this)->fcn_ptr(static_cast<Child*>(this), phit);
        }
        T (*fcn_ptr)(const Child &, const T &);
    private:
        static T fcn_default(const Child &obj, const T &phit){
            return 3.2 + phit;
        }
};

template<typename T> class Child1 : public Parent<Child1<T>,T>{
    public:
        Child1() {
        }
        T (*fcn_ptr)(const Child1 &, const T &);

};

template<typename T> class Child2 : public Parent<Child2<T>,T>{
    public:
        Child2() {
        }
        T (*fcn_ptr)(const Child2 &, const T &);

};

typedef double lrtType;

int main(){
    std::vector< Parent<lrtType> * > objects;

    Child1<lrtType> *test11 = new Child1<lrtType>();
    objects.push_back(test11);

    Child1<lrtType> *test12 = new Child1<lrtType>();
    test12->fcn_ptr = &fcn_mod1;
    objects.push_back(test12);

    Child2<lrtType> *test2 = new Child2<lrtType>();
    test2->fcn_ptr = &fcn_mod2;
    objects.push_back(test2);

for (size_t i = 0; i < objects.size(); ++i) {
        std::cout << objects[i]->do_something(2) << std::endl;
}

    cout << "test" << endl;
}

** +++++ UPDATE +++++ **

If I add a member to a child class, I can not have access to it from within fcn_mod2 for instance. Maybe the virtual functions can help?

#include <iostream>
#include <vector>
#include <cstdlib>

using namespace std;

template<typename T> class Parent;
template<typename T> class Child1;
template<typename T> class Child2;

template<typename T> T fcn_default(const Parent<T> &obj, const T &phit){
    return 3.2 + phit;
}
template<typename T> T fcn_mod1   (const Parent<T> &obj, const T &phit){
    return 1.2 + phit;
}
template<typename T> T fcn_mod2   (const Parent<T> &obj, const T &phit){
    return 2.2 + phit + param2*0.001;
}

template<typename T> class Parent{
    public:
        Parent() {
            fcn_ptr = &fcn_default;
        }
        T do_something(const T &phit){
            return this->fcn_ptr(*this, phit);
        }
        T (*fcn_ptr)(const Parent &, const T &);

};

template<typename T> class Child1 : public Parent<T>{
    public:
        Child1() {
        }

};

template<typename T> class Child2 : public Parent<T>{
    public:
        Child2() {
        }
        T param2;

};

typedef double lrtType;

int main(){
    std::vector< Parent<lrtType> * > objects;

    Child1<lrtType> *test11 = new Child1<lrtType>();
    objects.push_back(test11);

    Child1<lrtType> *test12 = new Child1<lrtType>();
    test12->fcn_ptr = &fcn_mod1;
    objects.push_back(test12);

    Child2<lrtType> *test2 = new Child2<lrtType>();
    test2->fcn_ptr = &fcn_mod2;
    test2->param2 = 4;
    objects.push_back(test2);

    for (size_t i = 0; i < objects.size(); ++i) {
        std::cout << objects[i]->do_something(2) << std::endl;
    }

    cout << "test" << endl;
}
Rufus
  • 15
  • 2
  • 8
  • 1
    So, what's the question? – polkovnikov.ph Jun 13 '14 at 13:52
  • 3
    This looks unnecessarily convolutive, the code is supposed to solve problems, not to create ones – Yulia V Jun 13 '14 at 13:53
  • 1
    I see you're [still at it](http://stackoverflow.com/questions/24195579/class-member-function-as-function-pointer), but have now upped the ante. Since you already have an inheritance hierarchy, why not use `virtual` functions for this? – Praetorian Jun 13 '14 at 13:58
  • @Praetorian: Indeed but the problem is different, hence the new post. Which one should I virtualize? – Rufus Jun 13 '14 at 14:02
  • @Rufus Add a `virtual` member function in `Parent` that does what `fcn_default()` is doing. The `Childx` classes can override that function in their implementations. Also, your `Parent` class needs a `virtual` destructor if you're planning on `delete`ing `Childx` objects via a `Parent *`. – Praetorian Jun 13 '14 at 14:22
  • @Rufus: Can you please elaborate why you need function pointers **at all** here? Just making those functions virtual methods seems to suffice. – gexicide Jun 13 '14 at 14:34
  • @Praetorian I can not do that as the function pointer can only point to static function member of a class. – Rufus Jun 13 '14 at 14:36
  • @gexicide These function pointers allow me to customize what an intance will do when `do_something` is called. If you know any other way of doing it that will also allow me to access all the members of its class, I'll take it. (I am not that litterate in C/C++ and still learning... Surprisingly) – Rufus Jun 13 '14 at 14:39
  • @Rufus Who said anything about function pointers? You don't need this funny business of having a function pointer data member that you keep assigning to different functions. Let the virtual function mechanism take care of all that. I'll post an example in a little while. – Praetorian Jun 13 '14 at 14:42
  • @gexicide @Praetorian To complement the question, I need to be able to change the behaviour of `do_something()` at the instance level and have access to all of its members. – Rufus Jun 13 '14 at 14:53
  • @Rufus Ah ok, I get it now, that wasn't clear from the question. In that case I'd prefer the `std::function` approach that I showed in my answer to your question yesterday. That way you're not limited to static member functions/free functions. – Praetorian Jun 13 '14 at 15:29
  • @Praetorian I have posted another question regarding a problem with std::function and std::bind here: http://stackoverflow.com/questions/24249909/no-matching-function-for-call-to-unresolved-overloaded-function-type – Rufus Jun 18 '14 at 10:20

1 Answers1

1

The problem that you have is that your child classes contain an other function pointer fields of the same name as the one in your Parent class. That is usually not what you want, since these classes will have two pointers in them. Why not simply use only one pointer in the parent class. So, you should delete the function pointers in the child classes.

The next problem you have in your second solution is that you try to use runtime virtual dispatch (the vector of Parents) with compile time "virtual" dispatch (the curiously recurring template pattern). This is just not possible. If you want runtime virtual dispatch, then you have to use virtual functions.

If there is no special reason for using function pointers, just use virtual methods only, i.e.:

template<typename T> class Parent{
public:
    virtual T fcn(const Parent<T> &obj, const T &phit){ return 3.2 + phit; }
};

template<typename T> class Child1 : public Parent<T>{
public:
    T fcn(const Parent<T> &obj, const T &phit) override { return 2.2 + phit; }
};

template<typename T> class Child2 : public Parent<T>{
public:
    T fcn(const Parent<T> &obj, const T &phit) override { return 1.2 + phit; }
};

That should work in your scenario. If this is not what you want, please clarify your question.

gexicide
  • 38,535
  • 21
  • 92
  • 152
  • You never assign anything to `ChildX::fcn_ptr` – gexicide Jun 13 '14 at 13:55
  • Oh, right, didn't see that. Editing my answer, mom. Well, what *is* your problem with the vector? – gexicide Jun 13 '14 at 13:57
  • The problem is that, in the for loop the method `do_something` is called for an object of class `Parent` it will therefore call `fcn_default`. Whereas I would like it to call the function where the function pointer points for the actual class `ChildX`. – Rufus Jun 13 '14 at 14:01
  • @Rufus Exactly. So why do you have a `fcn_ptr` in the derived class? And why don't you just use virtual functions? (Instead of the function pointer, add a virtual function to `Parent` and override it in each `ClassX`) – dyp Jun 13 '14 at 14:02