Acabei de encontrar o seguinte erro (e encontrei a solução online, mas ela não está presente no Stack Overflow):
(.gnu.linkonce. [coisas]): referência indefinida a [método] [arquivo de objeto] :(. gnu.linkonce. [coisas]): referência indefinida a `typeinfo for [classname] '
Por que alguém pode obter um desses erros de vinculador "referência indefinida ao typeinfo"?
(Pontos de bônus se você puder explicar o que está acontecendo nos bastidores.)
virtual void abc() =0;
(se a versão base nunca é chamado)abc()
assim, poderá facilmente esquecer de redefinirabc()
na classe derivada e pensar que está tudo bem, pois você ainda poderá chamar a função sem nenhum problema. Uma boa prática para implementar funções virtuais puras é encontrada neste artigo , e é para fazer a função imprimir "Função virtual pura chamada" e travar o programa.= 0;
.Respostas:
Uma razão possível é porque você está declarando uma função virtual sem defini-la.
Quando você o declara sem defini-lo na mesma unidade de compilação, indica que ele está definido em outro lugar - isso significa que a fase do vinculador tentará encontrá-lo em uma das outras unidades de compilação (ou bibliotecas).
Um exemplo de definição da função virtual é:
Nesse caso, você está anexando uma definição à declaração, o que significa que o vinculador não precisa resolvê-la posteriormente.
A linha
declara
fn()
sem defini-lo e causará a mensagem de erro sobre a qual você perguntou.É muito parecido com o código:
que indica que o número inteiro
i
é declarado em outra unidade de compilação que deve ser resolvida no momento do link (caso contrário,pi
não pode ser definido como seu endereço).fonte
virtual void fn() = 0
é uma definição. Não é uma definição, mas uma mera declaração . O único motivo pelo qual o vinculador não está tentando resolvê-lo é que a entrada VMT correspondente não fará referência a um corpo de função (provavelmente conterá um ponteiro nulo). No entanto, ninguém o proíbe de chamar essa função virtual pura de maneira não virtual, ou seja, usando um nome totalmente qualificado. Neste caso, o vinculador irá olhar para o corpo, e você terá que definir a função. E sim, você pode definir um corpo para uma função virtual pura.Isso também pode acontecer quando você mistura
-fno-rtti
e-frtti
codifica. Então você precisa garantir que qualquer classe, quetype_info
é acessada no-frtti
código, tenha seu método-chave compilado-frtti
. Esse acesso pode acontecer quando você cria um objeto da classe, usedynamic_cast
etc.[ fonte ]
fonte
Isso ocorre quando funções virtuais declaradas (não puras) estão em falta de corpos. Na sua definição de classe, algo como:
Deve ser definido (em linha ou em um arquivo de origem vinculado):
Ou declarado virtual puro:
fonte
Citando o manual do gcc :
E um pouco mais cedo na mesma página:
Portanto, esse erro ocorre quando o "método-chave" está ausente em sua definição, como outras respostas já mencionadas.
fonte
Se você está vinculando um .so a outro, mais uma possibilidade é compilar com "-fvisibility = hidden" no gcc ou no g ++. Se os dois arquivos .so foram criados com "-fvisibility = hidden" e o método-chave não é o mesmo. Assim como outra das implementações da função virtual, o último não verá a tabela ou o tipo de informação da primeira. Para o vinculador, isso parece uma função virtual não implementada (como nas respostas de paxdiablo e cdleary).
Nesse caso, você deve fazer uma exceção para a visibilidade da classe base com
na declaração de classe. Por exemplo,
Outra solução, é claro, é não usar "-fvisibility = hidden". Isso complica as coisas para o compilador e o vinculador, possivelmente em detrimento do desempenho do código.
fonte
As respostas anteriores estão corretas, mas esse erro também pode ser causado pela tentativa de usar typeid em um objeto de uma classe que não possui funções virtuais. O C ++ RTTI requer uma vtable, portanto, as classes nas quais você deseja executar a identificação de tipo exigem pelo menos uma função virtual.
Se você deseja que as informações de tipo trabalhem em uma classe para a qual você realmente não deseja nenhuma função virtual, torne o destruidor virtual.
fonte
Passei algumas horas com esse erro e, enquanto as outras respostas aqui me ajudaram a entender o que estava acontecendo, elas não resolveram o meu problema específico.
Estou trabalhando em um projeto que compila usando ambos
clang++
eg++
. Eu não estava tendo problemas de vinculação usandoclang++
, mas estava recebendo oundefined reference to 'typeinfo for
erro comg++
.O ponto importante: vincular a ordem MATTERS com
g++
. Se você listar as bibliotecas que deseja vincular em uma ordem incorreta, poderá obter otypeinfo
erro.Consulte esta pergunta SO para obter mais detalhes sobre como vincular ordem com
gcc
/g++
.fonte
Soluções possíveis para código que lida com bibliotecas RTTI e não RTTI:
a) Recompile tudo com -frtti ou -fno-rtti
b) Se a) não for possível para você, tente o seguinte:
Suponha que o libfoo seja construído sem o RTTI. Seu código usa libfoo e compila com RTTI. Se você usar uma classe (Foo) no libfoo que possui virtuais, é provável que você encontre um erro de tempo de link que diz: typeinfo ausente para a classe Foo.
Defina outra classe (por exemplo, FooAdapter) que não possui virtual e encaminhará as chamadas para o Foo que você usa.
Compile o FooAdapter em uma pequena biblioteca estática que não usa RTTI e depende apenas dos símbolos libfoo. Forneça um cabeçalho para ele e use-o no seu código (que usa RTTI). Como o FooAdapter não tem função virtual, ele não terá nenhuma informação de tipo e você poderá vincular seu binário. Se você usa muitas classes diferentes do libfoo, esta solução pode não ser conveniente, mas é um começo.
fonte
De maneira semelhante à discussão sobre RTTI, NO-RTTI acima, esse problema também pode ocorrer se você usar dynamic_cast e não incluir o código do objeto que contém a implementação da classe.
Encontrei este problema com base no Cygwin e depois portando código para o Linux. Os arquivos make, a estrutura de diretórios e até as versões gcc (4.8.2) eram idênticas nos dois casos, mas o código vinculava e operava corretamente no Cygwin, mas não conseguiu vincular no Linux. Aparentemente, o Red Hat Cygwin fez modificações no compilador / vinculador que evitam o requisito de vinculação do código do objeto.
A mensagem de erro do vinculador do Linux me direcionou corretamente para a linha dynamic_cast, mas as mensagens anteriores deste fórum me fizeram procurar por implementações de funções ausentes e não pelo problema real: código de objeto ausente. Minha solução alternativa foi substituir uma função de tipo virtual na classe base e derivada, por exemplo, virtual int isSpecialType (), em vez de usar dynamic_cast. Essa técnica evita o requisito de vincular o código de implementação de objeto apenas para fazer com que dynamic_cast funcione corretamente.
fonte
Na classe base (uma classe base abstrata), você declara um destruidor virtual e, como não pode declarar um destruidor como uma função virtual pura, é necessário defini-lo aqui na classe abstrata, apenas uma definição fictícia como virtual ~ base ( ) {} fará ou em qualquer classe derivada.
Se você não conseguir fazer isso, você terminará em um "símbolo indefinido" no momento do link. Como o VMT tem uma entrada para todas as funções virtuais puras com um NULL correspondente, ele atualiza a tabela dependendo da implementação na classe derivada. Mas para as funções não puras, mas virtuais, ele precisa da definição no momento do link para poder atualizar a tabela VMT.
Use c ++ filt para desmantelar o símbolo. Como $ c ++ filt _ZTIN10storageapi8BaseHostE, será exibido algo como "typeinfo para storageapi :: BaseHost".
fonte
Eu tenho muitos desses erros agora. O que aconteceu é que eu dividi uma classe somente de arquivo de cabeçalho em um arquivo de cabeçalho e um arquivo cpp. No entanto, não atualizei meu sistema de compilação, portanto o arquivo cpp não foi compilado. Entre simplesmente ter referências indefinidas para as funções declaradas no cabeçalho, mas não implementadas, recebi muitos desses erros typeinfo.
A solução foi executar novamente o sistema de compilação para compilar e vincular o novo arquivo cpp.
fonte
no meu caso, usei uma biblioteca de terceiros com arquivos de cabeçalho e, portanto, arquivo. subclassifiquei uma classe e erro de link como esse ocorreu quando tento instanciar minha subclasse.
como mencionado por @sergiy, sabendo que poderia ser o problema do 'rtti', consegui contorná-lo colocando a implementação do construtor em um arquivo .cpp separado e aplicando sinalizadores de compilação '-fno-rtti' ao arquivo . isso funciona bem.
Como ainda não estou muito claro sobre o erro interno deste link, não tenho certeza se minha solução é geral. no entanto, acho que vale a pena tentar antes de tentar o adaptador conforme mencionado por @francois. e, é claro, se todos os códigos-fonte estiverem disponíveis (não no meu caso), é melhor recompilar com '-frtti', se possível.
mais uma coisa, se você optar por tentar minha solução, tente tornar o arquivo separado o mais simples possível e não use alguns recursos sofisticados do C ++. tenha atenção especial em coisas relacionadas ao impulso, porque muito disso depende do rtti.
fonte
Eu tenho o mesmo erro quando minha interface (com todas as funções virtuais puras) precisava de mais uma função e eu esqueci de "anulá-la".
eu tinha
class ICommProvider { public: /** * @brief If connection is established, it sends the message into the server. * @param[in] msg - message to be send * @return 0 if success, error otherwise */ virtual int vaSend(const std::string &msg) = 0; /** * @brief If connection is established, it is waiting will server response back. * @param[out] msg is the message received from server * @return 0 if success, error otherwise */ virtual int vaReceive(std::string &msg) = 0; virtual int vaSendRaw(const char *buff, int bufflen) = 0; virtual int vaReceiveRaw(char *buff, int bufflen) = 0; /** * @bief Closes current connection (if needed) after serving * @return 0 if success, error otherwise */ virtual int vaClose(); };
O último vaClose não é virtual; portanto, o compilado não sabia onde obter a implementação e, portanto, ficou confuso. minha mensagem foi:
Mudança simples de
para
corrigiu o problema. espero que ajude
fonte
Encontro uma situação rara, mas isso pode ajudar outros amigos em situações semelhantes. Eu tenho que trabalhar em um sistema mais antigo com o gcc 4.4.7. Eu tenho que compilar o código com suporte ao c ++ 11 ou superior, então construo a versão mais recente do gcc 5.3.0. Ao criar meu código e vincular-me às dependências, se a dependência for criada com o compilador mais antigo, recebi o erro 'referência indefinida', mesmo que tenha definido claramente o caminho de vinculação com -L / path / to / lib -llibname. Alguns pacotes, como o boost e os projetos criados com o cmake, geralmente tendem a usar o compilador mais antigo e geralmente causam esses problemas. Você precisa percorrer um longo caminho para garantir que eles usem o compilador mais recente.
fonte
No meu caso, é puramente um problema de dependência de biblioteca, mesmo que eu tenha uma chamada dynamic_cast. Após adicionar dependência suficiente ao makefile, esse problema desapareceu.
fonte
Verifique se suas dependências foram compiladas sem
-f-nortti
.Para alguns projetos, você deve defini-lo explicitamente, como no RocksDB:
fonte
No meu caso, era uma função virtual em uma classe de interface que não foi definida como um virtual puro.
Eu esqueci um
= 0
pouco.fonte