【问题标题】:Template and class heritance模板和类继承
【发布时间】:2014-06-13 13:47:50
【问题描述】:

下面的代码没有产生我想要的。

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

它产生:

5.2
5.2
5.2
test

我期待:

5.2
3.2
4.2
test

我的理解是向量 objects 属于 Parent 类型,因此调用它自己的方法而不是孩子的方法。

我几乎用“奇怪的重复模板模式”破解了它,但在向量对象的初始化过程中我遇到了最后一个问题。

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

** +++++ 更新 +++++ **

如果我将成员添加到子类,例如,我无法从 fcn_mod2 中访问它。也许虚函数可以提供帮助?

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

【问题讨论】:

  • 那么,问题是什么?
  • 这看起来不必要的复杂,代码应该解决问题,而不是创建问题
  • 我知道你是still at it,但现在已经提高了赌注。既然您已经有了继承层次结构,为什么不为此使用virtual 函数呢?
  • @Praetorian:确实,但问题不同,因此是新帖子。我应该虚拟化哪一个?
  • @Rufus 在Parent 中添加一个virtual 成员函数,它执行fcn_default() 正在执行的操作。 Childx 类可以在其实现中覆盖该函数。此外,如果您计划通过 Parent * 处理 deleteing Childx 对象,您的 Parent 类需要 virtual 析构函数。

标签: c++ class templates


【解决方案1】:

您遇到的问题是您的子类包含与您的 Parent 类中的同名的其他函数指针字段。这通常不是您想要的,因为这些类中会有 两个 指针。为什么不简单地在父类中只使用一个指针。 所以,你应该删除子类中的函数指针。

您在第二个解决方案中遇到的下一个问题是您尝试使用 运行时虚拟调度Parents 的向量)和编译时“虚拟”调度(奇怪地重复出现的模板模式)。这是不可能的。如果你想要运行时虚拟调度,那么你必须使用 virtual 函数。

如果没有特殊原因使用函数指针,只使用虚方法即可,即:

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

这应该适用于您的场景。如果这不是您想要的,请澄清您的问题。

【讨论】:

  • 你永远不会给ChildX::fcn_ptr分配任何东西
  • 哦,对了,没看到。编辑我的答案,妈妈。那么,您对向量的问题是什么
  • 问题在于,在 for 循环中,方法 do_something 被调用为类 Parent 的对象,因此它将调用 fcn_default。而我希望它调用函数指针指向实际类ChildX的函数。
  • @Rufus 没错。那么为什么派生类中有fcn_ptr 呢?为什么不直接使用虚函数呢? (代替函数指针,给Parent添加一个虚函数,并在每个ClassX中覆盖)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 2019-11-25
  • 2018-05-23
  • 1970-01-01
相关资源
最近更新 更多