Pergunta

Estou recebendo erros de ligação do seguinte tipo:

Festival.obj: erro LNK2019: não resolvido símbolo externo "pública: vazio __thiscall Árvore :: add (classe Price &)" (? Adicionar @? $ Árvore @ VPrice @@@@ QAEXAAVPrice @@@ Z) referenciado na função __catch $? AddBand @ Festival @@ QAE? AW4StatusType @@ HHH @ Z $ 0

Eu costumava pensar que isso tem a ver com o mecanismo de try-catch, mas desde que foi dito de outra forma. Esta é uma versão atualizada da questão.

Estou usando o Visual Studio 2008, mas não tenho problemas semelhantes em g ++.

O código relevante:

Em Festival.cpp

#include "Tree.h"
#include <exception>

using namespace std;

class Band{
public:
    Band(int bandID, int price, int votes=0): bandID(bandID), price(price), votes(votes){};
...
private:
...

};

class Festival{
public: 
    Festival(int budget): budget(budget), minPrice(0), maxNeededBudget(0), priceOffset(0), bandCounter(0){};
    ~Festival();
    StatusType AddBand(int bandID, int price, int votes=0);
    ...

private: 
    Tree<Band> bandTree;
    ...

};

StatusType Festival::AddBand(int bandID, int price, int votes){
    if ((price<0)||(bandID<0)){
        return INVALID_INPUT;
    }
    Band* newBand=NULL;
    try{
        newBand=new Band(bandID,price-priceOffset,votes);
    }
    catch(bad_alloc&){return ALLOCATION_ERROR;}
    if (bandTree.find(*newBand)!=NULL){
        delete newBand;
        return FAILURE;
    }
bandTree.add(*newBand);
....
}

Em Tree.h:

template<class T>
class Tree{
public:
    Tree(T* initialData=NULL, Tree<T>* initialFather=NULL);
    void add(T& newData);
....
private:
....
};

Curiosamente eu não tenho erros de ligação quando tento usar funções de árvore quando o tipo T é um tipo primitivo como um int.

Foi útil?

Solução

Existe Tree.cpp? Se houver, talvez você se esqueceu de ligá-lo? Onde está a implementação de árvore :: add? Além disso, não vejo onde você chamar Árvore :: add. Eu acho que deve estar dentro do try, logo após o novo?

Apenas um lembrete:

Para a maioria dos compiladores (ou seja, aqueles que a prática compilação separada) a implementação das funções de membro de uma classe de modelo tem que ser visível durante a compilação do arquivo de origem que utiliza a classe de modelo. Normalmente as pessoas seguem esta regra, colocando a implementação das funções de membro de dentro do arquivo de cabeçalho.

Talvez Árvore :: add não é dentro do cabeçalho? Em seguida, uma possível solução no caso discutido será colocar implementação Árvore :: add dentro do arquivo de cabeçalho.

A diferença entre as classes regulares e classes de modelo existe porque classes de modelo não são aulas "reais" - é, também, um modelo. Se você tinha definido sua classe de árvore como uma classe regular, o compilador poderia ter usado o código de imediato. No caso de um modelo o compilador primeiro "escreve" para você a classe real, substituindo os parâmetros do modelo com os tipos fornecidas. Agora, o compilador compila cpp arquivos um por um. Ele não tem conhecimento de outros arquivos CPP e pode usar nada de outros arquivos CPP. Vamos dizer que sua implementação de árvore: olhares add como este:

void Tree::add(T& newData)
{
    newData.destroyEverything();
}

É totalmente legítimo, desde que seu T tem método destroyEverything. Quando o compilador compila Class.cpp ele quer ter certeza de que você não fazer com T qualquer coisa que não sabe. Por exemplo Tree<int> não vai funcionar porque int não tem destroyEverything. O compilador irá tentar escrever o seu código com int em vez de T e descobrir que o código não compila. Mas desde que o compilador "vê" apenas o CPP atual e tudo o que inclui, não será capaz de função Validar add, uma vez que está em um CPP separado.

Não haverá qualquer problema com

void Tree::add(int& newData)
{
    newData.destroyEverything();
}

implementada em um CPP em separado porque o compilador sabe que int é o tipo só é aceitável e pode "contar com si mesmo" que quando ele começa a compilar Tree.cpp ele vai encontrar o erro.

Outras dicas

Tem certeza que o try / catch tem nada a ver com isso? O que acontece se você simplesmente comentar as linhas try e catch, deixe o resto do código como está, e construir isso?

Pode ser que você está perdendo a biblioteca que define Tree::add(class Price &) de sua linha de ligação.

Update: usando funções árvore com um tipo primitivo não resulta em um erro de ligação. Eu atualizei a minha pergunta à luz de algumas das coisas que foram ditas.

Como os outros, você precisa mostrar a implementação de Treee :: add () e diga-nos como você está ligando-o.

Em um ponto relacionado, se você estiver usando construções como:

  Band* newBand=NULL;
    try{
        newBand=new Band(bandID,price-priceOffset,votes);
    }
    catch(bad_alloc&){return ALLOCATION_ERROR;}

em todo o código, você está francamente desperdiçando seu tempo. As chances de você chegar a um ponto de exaustão de memória em um sistema operacional moderno são remotas e as chances de você fazer qualquer coisa útil depois que ele aconteceu são aproximadamente zero. Você vai ser muito melhor simplesmente dizendo:

Band * newBand = new Band ( bandID, price - priceOffset, votes );

ot possivelmente:

Band newBand( bandID, price - priceOffset, votes );

e esquecer a manipulação de exceção neste caso.

Você escreveu em um comentário:

Eu considerei isso, mas a função é parte de Tree.h, e eu incluí-lo. A função definida é: template vazio Árvore :: add (T & newData); Chamamos-lhe da seguinte maneira: priceTree.add (* newPriceNode); enquanto priceTree é Árvore, ambos os quais são definidos no arquivo cpp em questão.

em vez de:

priceTree.add(*newPriceNode);

tentar:

priceTree.add(newPriceNode); //no "*" before "newPriceNode"

add () leva uma referência a um nó, não um ponteiro para um nó (de acordo com a sua definição de árvore).

Você está recebendo erros de ligação, os erros não compilador. Isso nos diz que o compilador sabia que tipo de função Tree::add() é, mas não tem uma definição. Em Tree.h, vejo uma declaração da função add (), mas não uma definição. Parece estranho para mim; Alguém sabe onde Tree.h veio?

Normalmente, uma classe de modelo vem com definições de funções membro no arquivo de inclusão, uma vez que as funções tem que estar em algum lugar instanciado, ea coisa mais simples é para o compilador para instanciar quando usado e deixar o vinculador classificar. Se as definições estão em Tree.h, eu esperaria que tudo funcione como o planejado.

Então, eu vou sair em um membro e sugerem que as definições estão em um arquivo separado, não ligada, e que existem disposições em outra parte para instanciar para tipos básicos como Tree<int>. Este é presumivelmente para compilação agilizar, como normalmente estas coisas são compilados em vários lugares, e isso leva tempo.

O que você precisa fazer nesse caso é encontrar onde Tree<int> é instanciado, e adicionar uma instância para a sua classe.

Eu poderia estar longe de base aqui, mas a minha explicação se encaixa nos fatos que você deu.

Editar após as primeiras observações :

Os modelos são um pouco mais complicado do que funções ordinárias, o que geralmente não é um problema real. Se as definições para todas as chamadas estavam em Tree.h, então Festival.cpp seria capaz de Tree<Band> instanciar e tudo seria legal. Essa é a técnica habitual, e você está correndo para este problema, porque você não está usando-o.

Quando você escrever uma função, ele é compilado e o vinculador irá encontrá-lo. Qualquer rotina de chamar essa função precisa saber o protótipo da função, por isso vai saber como chamá-lo. Quando você escreve um modelo, você não está escrevendo qualquer coisa que irá diretamente para o programa, mas qualquer uso das contagens modelo como escrever todas as funções.

Por isso, tem de haver algum uso de algum lugar Tree<Band> em seu programa, para que haja uma função Tree<Band>::add() compilado. A definição de Tree<T>::add tem de estar disponível para o compilador quando Tree<Band> é instanciado, porque caso contrário o compilador não tem idéia do que para compilar. Neste caso, está gerando a chamada de função, confiante de que você vai ter certeza de que a função é compilado em outro lugar.

Portanto, você tem que Tree<Band> instanciar dentro de um arquivo que tem acesso a ambas as definições para Tree<T> e Band. Isso provavelmente significa um arquivo que é, ou inclui, Tree.cpp e inclui Festival.h.

O vinculador já está usando Tree.cpp, mas não Tree.cpp não tem Tree<Band> definido nele, por isso é sem sentido para o vinculador. Os modelos são úteis apenas para o compilador e o vinculador só funciona sobre o que o compilador gerado a partir de modelos.

A forma mais rápida de resolver isso é para levar as definições de Tree.cpp e colocá-los em Tree.h. Que será provavelmente a aumentar o tempo de compilação e de link, infelizmente. A outra técnica é instanciar todos os usos de modelo no Tree.cpp, de modo que eles vão ser compilado lá.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top