2009-11-17 5 views
0

j'ai écrit un code, mais je suis incapable de le compiler:tables virtuelles ne sont pas définies

 
#include <cstdio> 
#include <vector> 

using namespace std; 

class Visitor; 

class Land { 
    public: 
    virtual void accept(const Visitor *v); 
}; 

class England : public Land { 
    public: 
    void accept(const Visitor *v); 
}; 

class Russia : public Land { 
    public: 
    void accept(const Visitor *v); 
}; 

class Visitor { 
    public: 
    void visit(const England *e) const; 
    void visit(const Russia *r) const; 
}; 

class Trip { 
    private: 
    vector<Land> *l; 
    public: 
    explicit Trip(vector<Land> *_l); 
    void accept(Visitor *v); 
}; 

/**/ 

void Visitor::visit(const England *e) const { 
    printf("Hey, it's England!\n"); 
} 

void Visitor::visit(const Russia *r) const { 
    printf("Hey, it's Russia!\n"); 
} 

void Russia::accept(const Visitor *v) { 
    v->visit(this); 
} 

void England::accept(const Visitor *v) { 
    v->visit(this); 
} 

Trip::Trip(vector<Land> *_l):l(_l) {} 

void Trip::accept(Visitor *v) { 
    for (unsigned i = 0; i < l->size(); i++) { 
    l->at(i).accept(v); 
    } 
} 

int main() { 
    England england; 
    Russia russia; 
    vector<Land> trip_plan; 
    trip_plan.push_back(england); 
    trip_plan.push_back(russia); 
    trip_plan.push_back(england); 
    Trip my_trip(&trip_plan); 
    Visitor me; 
    my_trip.accept(&me); 
    return 0; 
} 

C'est ce que je suis de g ++:

 
c++ -ansi -Wall -Wextra -Wconversion -pedantic -Wno-unused-parameter -o vp vp.cc 
/tmp/ccNanCPR.o: In function `Land::Land()': 
vp.cc:(.text._ZN4LandC2Ev[Land::Land()]+0xf): undefined reference to `vtable for Land' 
/tmp/ccNanCPR.o: In function `Land::Land(Land const&)': 
vp.cc:(.text._ZN4LandC1ERKS_[Land::Land(Land const&)]+0x13): undefined reference to `vtable for Land' 
/tmp/ccNanCPR.o: In function `Land::~Land()': 
vp.cc:(.text._ZN4LandD1Ev[Land::~Land()]+0xf): undefined reference to `vtable for Land' 
/tmp/ccNanCPR.o:(.rodata._ZTI6Russia[typeinfo for Russia]+0x10): undefined reference to `typeinfo for Land' 
/tmp/ccNanCPR.o:(.rodata._ZTI7England[typeinfo for England]+0x10): undefined reference to `typeinfo for Land' 
collect2: ld returned 1 exit status 

Cette question est basée sur Circular dependencies of declarations

+0

connexes, mais je ne comprends pas: http: // gcc.gnu.org/faq.html#vtables – Martin

+0

Ces deux instructions vides #include sont-elles intentionnelles? –

+0

désolé .. problème de formation – Martin

Répondre

6

Je déjà answered là-bas. Les règles d'instanciation vtable sont expliquées dans la documentation de votre compilateur.

Ici, il est en attente de voir la définition (corps) de Land :: accept, que vous avez déclaré être un virtuel non pur, mais jamais défini. Vous pouvez le définir ou le rendre purement virtuel.

+0

Je pense que je l'ai maintenant. Merci beaucoup. – Martin

2

Si vous n'exécutez pas de fonction virtuelle (c'est-à-dire si elle doit être remplacée par des descendants), vous devez la marquer comme telle via '= NULL' (elle s'appelle alors fonction virtuelle pure).

class Land { 
    public: 
    virtual void accept(const Visitor *v)= 0; // pure virtual function 
}; 
+0

Je pense que l'usage commun est = 0. Bien qu'en C++ NULL soit défini comme 0, vous risquez de confondre les autres avec cette notation et la confusion est mauvaise. –

+0

Merci. Je ne savais pas que les marques '= 0' fonctionnent de manière purement virtuelle. Prochaine leçon apprise. – Martin

+0

Martin a raison, ça devrait être "= 0" ... – Nicholaz

1

Implémenter la méthode Land :: accept ou la déclarer comme virtuelle pure.

Cependant, j'ai repéré un problème possible dans le principal:

trip_plan.push_back(england); 
trip_plan.push_back(russia); 
trip_plan.push_back(england); 

Je ne sais pas ce que vecteur de type est, mais vous pourriez avoir un problème fournir des objets de classe dérivée à insérer dans un vecteur de classe de base valeurs (Type Slicing).

+0

Oui, il y a même une question SO pour ça: http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in -c –

+0

Oui, j'ai eu un problème avec ça mais j'ai utilisé quelques pointeurs pour m'en débarrasser. Mais cela m'a dérouté pendant un moment. – Martin

+0

C'est le mot dont j'étais incapable de me souvenir! Trancher! –

0

Je vois deux choses:

1) Notez les disparus "<" avant la taille

void Trip::accept(Visitor *v) { 
    for (unsigned i = 0; i < size(); i++) { 
    l->at(i).accept(v); 
    } 
} 

2) Je pense (en supposant que je comprends votre exemple correctement) vecteur devrait être vecteur < Land> (vous construisez un vecteur de résumé des terres qui est ensuite rempli avec des pointeurs vers des objets en béton Land)

vector<Land> Trip; 

ou

typedef vector<Land> trip_t; // type for a trip is a vector of Lands 
... 

trip_t Trip; 

(Il semble que vous êtes en train d'éditer l'échantillon pendant que j'écris ce commentaire, donc je vais devoir aller avec une réponse plus générale).

+0

Je suis désolé .. Le puissant traitement de texte stackoverflow ne peut pas gérer le < and > – Martin

0

Je pense que lorsque vous utilisez vector, vous devriez utiliser std::vector<Land*>:

class Trip { 
    private: 
    std::vector<Land*> *l; // vector of pointers to Land 
    public: 
    explicit Trip(std::vector<Land*> *_l); 
    void accept(Visitor *v); 
}; 

et

void Trip::accept(Visitor *v) { 
    for (unsigned i = 0; i< l->size(); i++) { 
    l->at(i)->accept(v); // . changed to -> 
    } 
} 

et

int main() { 
    England england; 
    Russia russia; 
    std::vector<Land*> trip_plan; 
    trip_plan.push_back(&england); // push_back pointers 
    trip_plan.push_back(&russia); 
    trip_plan.push_back(&england); 
    Trip my_trip(&trip_plan); 
    Visitor me; 
    my_trip.accept(&me); 
    return 0; 
} 

Vous devez utiliser <Land*> afin que vous ne 't tranche england et russia en dans positions de Land. En outre, vous pourriez penser à utiliser un itérateur dans Trip::accept la prochaine fois.

0

Ok, voici un exemple de travail complet (je ne sais pas si vous avez été coupé du vôtre). Il compile ici et j'ai marqué tous les endroits où j'ai fait des changements avec "!!!" Commentaires:

#include <cstdio> 
#include <vector> 

using namespace std; 

class Visitor; 

class Land { 
    public: 
    virtual void accept(const Visitor *v)= 0; // !!! = 0 
}; 

class England : public Land { 
    public: 
    void accept(const Visitor *v); 
}; 

class Russia : public Land { 
    public: 
    void accept(const Visitor *v); 
}; 

class Visitor { 
    public: 
    void visit(const England *e) const; 
    void visit(const Russia *r) const; 
}; 


class Trip { 
    private: 
    vector<Land *> *l;   // !!! <Land *> 

    public: 
    Trip(vector<Land *> *_l); // !!! <Land *> 
    void accept(Visitor *v); 
}; 


/* Implementations */ 

void Visitor::visit(const England *e) const { 
    printf("Hey, it's England!\n"); 
} 

void Visitor::visit(const Russia *r) const { 
    printf("Hey, it's Russia!\n"); 
} 

void Russia::accept(const Visitor *v) { 
    v->visit(this); 
} 

void England::accept(const Visitor *v) { 
    v->visit(this); 
} 

Trip::Trip(vector<Land *> *_l) : l(_l) // !!! <Land *> 
{ 

} 

void Trip::accept(Visitor *v) { 

    for (unsigned i = 0; i < l->size(); i++) {  // !!! i < l->size() 
    l->at(i)->accept(v);       // !!! at(i)->accept() 
    } 
} 

int main() 
{ 
    England england; 
    Russia russia; 

    vector<Land *> trip_plan;   // !!! <Land *> 

    trip_plan.push_back(&england); // !!! &england 
    trip_plan.push_back(&russia);  // !!! &russia 
    trip_plan.push_back(&england); // !!! &england 

    Trip my_trip(&trip_plan); 
    Visitor me; 
    my_trip.accept(&me); 

    return 0; 
} 
1

Cela est probablement va bien au-delà de ce que vous demandez, mais d'un point de vue de la conception, je pense que les choses spécifiques des terres devrait être à l'intérieur de la classe de chaque pays, à savoir ça me énerve un peu pour voir le fonction visit() surchargée dans Visitor.

Le membre accept() pour la Russie et l'Angleterre d'un autre côté est le même, et devrait être déplacé dans le Land.

Voici comment je structurer (jeter un oeil à l'utilisation d'accepter(), arriver() et le nom()):

#include <cstdio> 
#include <vector> 

using namespace std; 

class Visitor; 

class Land { 

    public: 
    virtual void accept(const Visitor *v); 

    virtual void arrive(void) const = 0; 
    virtual const char *name(void) const = 0; 

}; 

class England : public Land { 
    public: 
    void arrive(void) const; 
    const char *name(void) const; 
}; 

class Russia : public Land { 
    public: 
    void arrive(void) const; 
    const char *name(void) const; 
}; 

class Visitor { 
    public: 
    void visit(const Land *l) const; 
}; 


class Trip { 
    private: 
    vector<Land *> *l; 

    public: 
    Trip(vector<Land *> *_l); 
    void accept(Visitor *v); 
}; 


/**** Implementations *****/ 

// underlying Land 

void Land::accept(const Visitor *v) { 
    v->visit(this); 
} 


// England 

const char *England::name(void) const { 
    return "England"; 
} 

void England::arrive(void) const { 
    printf("Welcome to our lovely country, your passport please\n"); 
} 


// Russia 

const char *Russia::name(void) const { 
    return "Russia"; 
} 

void Russia::arrive(void) const { 
    printf("Passport!!\n"); 
} 


// Visitor 

void Visitor::visit(const Land *l) const { 
    l->arrive(); 
    printf("Hey, it'm in %s!\n", l->name()); 
} 



// Trip 

Trip::Trip(vector<Land *> *_l) 
    : l(_l) // !!! <Land *> 
{ 

} 

void Trip::accept(Visitor *v) { 

    for (unsigned i = 0; i < l->size(); i++) {  
    l->at(i)->accept(v);       
    } 
} 



/**** main *****/ 

int main() 
{ 
    England england; 
    Russia russia; 

    vector<Land *> trip_plan;  

    trip_plan.push_back(&england);  
    trip_plan.push_back(&russia);  
    trip_plan.push_back(&england); 

    Trip my_trip(&trip_plan); 
    Visitor me; 
    my_trip.accept(&me); 

    return 0; 
} 
Questions connexes