c++ - 在 main 函数调用期间使用 main 上面的模板类给出错误

标签 c++

我在 main.cpp 的 main 上面定义了一个基类和一个子类 这给了我一个 undefined reference 的错误 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;
}

最佳答案

C++ 中的接口(interface)称为 "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 输出[T];//T 从命令行读取

使用 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)

关于c++ - 在 main 函数调用期间使用 main 上面的模板类给出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44070653/

相关文章:

.net - OracleConnection 在托管 C++ 中抛出 EEMessageException

c++ - 这是对 dynamic_cast 的正确使用吗?

c++ - 避免 Switch 语句中的分支操作

c++ - 尝试进行多态性时出现 c2011 错误 c++

c++ - std::cin 上的 std::getline

C++ 错误 1 ​​错误 C2146 : syntax error: missing ';' before identifier 'records'

c++ - 我们可以在 Windows 上使用 .so 文件吗?

c++ - 如何用数组初始化 glm::mat4?

c++ - 使 GCC 和其他 C++ 编译器非常严格

c++ - boost::interprocess 共享内存删除对象而不破坏