在main中的函数调用期间使用主要给出错误的模板类

时间:2017-05-19 12:51:42

标签: c++

我正在使用main.cpp中主要定义的基类和子类 这给了我一个未定义引用的错误:FactoryTraversal :: AddPoint :: AddPoint(int const&,int const&,int)' 这是代码:

#include <iostream>
#include <list>
#include <typeinfo>
#include <cmath>

enum traversal_type
{
    TRAVERSAL = 0,
    TRAVERSALMAX
};

template <class T>
class FactoryTraversal
{
public:
    FactoryTraversal();
    FactoryTraversal *CreateInstance(const traversal_type &type);
    virtual ~FactoryTraversal();
    const std::list<int>& GetIndices() const {return indices;}
    int GetIndicesSize() const {return indices.size();}
    virtual void AddPoint(const T &x, const T &y, int index);
protected:
    std::list<int> indices;
};

template<class T>
class Traversal : public FactoryTraversal<T>
{
public:
    Traversal();
    void AddPoint(const T &x, const T &y, int index);
    int GetResultXOR() const {return result_xor;}
private:
    T coords_s[2];
    T coords_e[2];
    int result_xor;
    void update_result(int index);
    T calculate_distance(const T &x1, const T &x2, const T &y1, const T &y2);
};
template<class T>
Traversal<T>::Traversal():FactoryTraversal<T>()
{
    //Do nothing
}
template<class T>
void Traversal<T>::AddPoint(const T &x, const T &y, int index)
{
    if (0 == this->GetIndicesSize())
    {
        this->indices.push_front(index);
        coords_s[0] = x; coords_s[1] = y;
        coords_e[0] = x; coords_e[1] = y;
    }
    else
    {
        T d1 = this->calculate_distance(x,coords_s[0],y,coords_s[1]);
        T d2 = this->calculate_distance(x,coords_e[0],y,coords_e[1]);
        if (d1 < d2)
        {
            this->indices.push_front(index);
            coords_s[0] = x; coords_s[1] = y;
        }
        else
        {
            this->indices.push_back(index);
            coords_e[0] = x; coords_e[1] = y;
        }
    }
    this->update_result(index);
}
template<class T>
T Traversal<T>::calculate_distance(const T &x1, const T &x2, const T &y1, const T &y2)
{
    if (typeid(T) == typeid(int))
    {
        return std::min(std::abs(x1-x2),std::abs(y1-y2));
    }
    return 0;
}
template<class T>
void Traversal<T>::update_result(int index)
{
    if (0 == this->GetIndicesSize())
        result_xor = index;
    else
        result_xor ^= index;
}
template<class T>
FactoryTraversal<T>::FactoryTraversal()
{
    indices.clear();
}
template<class T>
FactoryTraversal<T>::~FactoryTraversal()
{
    //Do Nothing
}
template<class T>
FactoryTraversal<T>* FactoryTraversal<T>::CreateInstance(const traversal_type &type)
{
    if (TRAVERSAL == type)
        return new Traversal<T>();
    else
        return NULL;
}

FactoryTraversal<int> factory_traversal;
Traversal<int> *traversal = new Traversal<int>();

int main()
{
    int T;
    std::cin>>T;
    int output[T];
    for (int i = 0; i < T; ++i)
    {
        int N;
        std::cin>>N;
        FactoryTraversal<int> factory_traversal;
        FactoryTraversal<int> *traversal = factory_traversal.CreateInstance(TRAVERSAL);
        for (int j = 0; j < N; ++j)
        {
            int x, y;
            std::cin>>x>>y;
            traversal->AddPoint(x,y,j+1);
        }
        Traversal<int> *tmp = dynamic_cast<Traversal<int> *>(traversal);
        if (tmp)
            output[i] = tmp->GetResultXOR();
        else
            output[i] = 0;
    }
    for (int i = 0; i < T; ++i)
    {
        std::cout<<output[i]<<std::endl;
    }
    return 0;
}

1 个答案:

答案 0 :(得分:1)

C ++中的接口称为"abstract classes",如果类至少有一个“纯虚函数”,则类是抽象的。如果函数的前缀为virtual并且其声明中有=0,则该函数是纯虚函数。这就是你想要的FactoryTraversal::AddPoint

virtual void AddPoint(const T &x, const T &y, int index) = 0;

现在期望派生类定义它(它确实如此)。如果AddPoint不是纯虚拟的,那么您将被迫在基类中为它提供一个实现,您可以这样做:

virtual void AddPoint(const T &x, const T &y, int index){}

这为衍生类选择不覆盖该方法时提供了“默认”或回退实现。如果它是纯虚拟的,派生类是强制来定义它,以免对它的调用导致编译器错误(否则派生类也被认为是抽象的)。

请注意,析构函数永远不应该是纯虚拟的。你现在的方式很棒;你无意识地遵循了我上面概述的规则。

其他一些说明:

  • 可变长度数组不是合法的C ++,这是编译器扩展:

    int output[T]; // T is read from command line

改为使用vector

 std::vector<int> output(T);
  • 您的内存泄漏原样。使用unique_ptr之类的托管指针,这样您就不必担心newdelete

  • 我说你希望AddPoint是纯虚拟的,我的意思是。但是,如果这是您采取的第一步,则代码将无法编译。看起来您将基类和工厂合并为一个;把那些分开了。

总而言之,我们可以将新的基类定义为:

template<class T>
class TraversalBase
{
public:
    virtual ~TraversalBase(){}
    const std::list<int>& GetIndices() const {return indices;}
    int GetIndicesSize() const {return indices.size();}
    virtual void AddPoint(const T &x, const T &y, int index) = 0;
protected:
    std::list<int> indices; 
};

派生类变为(变化很小,也注意到override关键字):

template<class T>
class Traversal : public TraversalBase<T>
{
public:
    void AddPoint(const T &x, const T &y, int index) override;
    int GetResultXOR() const {return result_xor;}
private:
    T coords_s[2];
    T coords_e[2];
    int result_xor;
    void update_result(int index);
    T calculate_distance(const T &x1, const T &x2, const T &y1, const T &y2);
};

我们的Factory类非常简化:

template <class T>
struct FactoryTraversal
{
    FactoryTraversal(){}
    std::unique_ptr<TraversalBase<T>> CreateInstance(const traversal_type &type);
    ~FactoryTraversal(){}
};

Live Demo(C ++ 11)