2017-05-19 1 views
2

Ich benutze eine Basisklasse und eine Kindklasse definiert über Main in main.cpp dies gibt mir einen Fehler der nicht definierten Referenz FactoryTraversal :: AddPoint :: AddPoint (int const &, int const &, int)‘ Hier ist der Code:mit Vorlage Klassen über Hauptgabe Fehler beim Funktionsaufruf in Haupt

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

AddPoint sollte in der Basisklasse rein virtuell sein. –

+0

Mögliches Problem: 'FactoryTraversal * traversal = factory_traversal.CreateInstance (TRAVERSAL);' in main ist Shadowing eine globale; 'factory_traversal' in main beschattet auch. Auch 'Fehler: ISO C++ verbietet variable Länge Array 'output'' –

+1

Sie definiert nie virtual void AddPoint (const T & amp; x, const T & y, int index); – NathanOliver

Antwort

1

Interfaces in C++ "abstract classes" genannt werden, und Klassen sind abstrakt, wenn sie mindestens ein "rein virtuelle Funktion" haben. Eine Funktion ist eine reine virtuelle Funktion, wenn ihr das Präfix virtual vorangestellt ist und in ihrer Deklaration ein =0 folgt. Dies ist, was Sie wollen für FactoryTraversal::AddPoint:

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

Nun ist die abgeleitete Klasse zu definieren ist zu erwarten (und es tut). Ohne AddPoint rein virtuell ist, sind Sie eine Implementierung für sie in der Basisklasse zu schaffen gezwungen, die Sie tun können, einfach als:

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

Dies ergibt eine „default“ oder Ausweich-Implementierung für, wenn eine abgeleitete Klasse wählt nicht um die Methode zu überschreiben. Wenn es rein virtuell wäre, ist die abgeleitete Klasse forciert, um es zu definieren, damit ein Aufruf zu ihm in einem Compiler-Fehler resultiert (andernfalls wird die abgeleitete Klasse auch als abstrakt betrachtet).

Beachten Sie, dass Destruktoren niemals rein virtuell sein sollten. Die Art, wie Sie es jetzt haben, ist großartig; Sie haben unbewusst die oben beschriebenen Regeln befolgt.

Einige andere Hinweise:

  • variabler Länge Arrays sind nicht legal C++, das ist eine Compiler-Erweiterung:

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

Verwenden Sie einen vector statt:

std::vector<int> output(T); 
  • Sie haben Speicherverluste, wie sie sind. Verwenden Sie einen verwalteten Zeiger wie unique_ptr, so dass Sie sich keine Gedanken über new und delete Sorge

  • ich festgestellt, dass Sie AddPoint wollte virtuelle rein sein und ich meine es ernst. Dein Code wird nicht kompiliert, wenn das der erste Schritt ist. Es sieht so aus, als hättest du eine Basisklasse und eine Fabrik in eine zusammengefasst. spaltet diese heraus.

es Putting alle zusammen können wir unsere neue Basisklasse definieren als:

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

Die abgeleitete Klasse wird (sehr geringe Änderung, beachten Sie auch den override Stichwort):

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

Und unsere Factory-Klasse ist stark vereinfacht:

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

Live Demo (C++ 11)

Verwandte Themen