Template and class heritance

孤人 提交于 2019-12-25 03:26:34

问题


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;
}

回答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.



来源:https://stackoverflow.com/questions/24206909/template-and-class-heritance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!