【问题标题】:Helper understanding linker error LNK2019帮助理解链接器错误 LNK2019
【发布时间】:2017-04-07 17:21:21
【问题描述】:

我知道这里有很多关于这个主题的问题,但我在我的代码中找不到未引用的符号。

这是错误:

错误 LNK2019:未解析的外部符号“public: __thiscall MyString::MyString(char const *)”(??0MyString@@QAE@PBD@Z) 在函数“public: __thiscall Fahrzeug::Fahrzeug(char *) " (??0Fahrzeug@@QAE@PAD@Z)

这是创建的字符串类的标头:

#ifndef MyString_h
#define MyString_h

#include <ostream>

using namespace std;


class MyString{

    char *strPtr=nullptr;
    unsigned int strSize;
    unsigned int strCapacity;
public:
    //Standardkonstruktor
    MyString();
    //Konvertierkonstruktor
    MyString(const char *);
    //Kopierkonstruktor
    MyString(const MyString&);
    //Destruktor
    ~MyString();


    void reserve(unsigned int c);
    MyString & append(MyString & );
    MyString & assign(MyString & );

    unsigned int size();
    unsigned int capacity();
    void clear();
    bool empty();
    const char* c_str();

    char  &at( int);

    MyString operator+( MyString &);
    bool operator==(const MyString &);
    MyString operator=(MyString &);
    friend ostream & operator<<(ostream &, MyString);
};

//MyString operator+(const MyString &);
//MyString operator==(const MyString &, const MyString &);
//MyString operator[]( MyString &);
//MyString operator<<(const MyString &);

#endif

这是 mystring 类的 cpp 文件

    #include "MyString.hpp"
    #include <ostream>
    using namespace std;
    #include <cstring>



    //Hausaufgabe 2 Eigene String Klasse Teil 1

    //Standardkonstruktor legt leeren String an 
    MyString::MyString()
    :strCapacity(1), strSize(0)
    {

        this->strPtr = new char[strCapacity];
        /*this->strPtr[0] = "\0";*/
    }


    // Konvertierkonstruktor wandelt C-String in MyString um
    MyString::MyString(const char  * string){

        //größe String herausfinden
        unsigned int i = strlen(string);
        //Größe und Kapazität des Strings festlegen
        this->strCapacity = i;
        this->strSize = i;
        // Dynamisches Array Erzeugen. i+1 für abschließendes  "\0" Zeichen
        this->strPtr = new char[i+1];
        //string in strPtr kopieren
        strncpy(this->strPtr, string, i);

        //Abschließendes "\0" Zeichen einfügen
        this->strPtr[i] = '\0';
    }

    MyString::MyString( const MyString & old){
        //Tiefe Kopie von old anlegen
        int size = int(strlen(old.strPtr));
        strPtr = new char[size];  
        strncpy(strPtr, old.strPtr, old.strSize);
        this->strSize = int(strlen(old.strPtr));
        this->strCapacity = old.strCapacity;
        this->strPtr[this->strSize] = '\0';
    }

    MyString::~MyString(){
        // Freigegebener Speicher wird wieder gelöscht
        delete[] this->strPtr;
        strPtr = nullptr;
    }

    void MyString::reserve(unsigned int c){
        //prüfen ob Speicherplatz benötigt wird

            //reservespeicher wird angelegt und String wird gesichert
            char *temp = new char[this->strSize];
            strncpy(temp,this->strPtr,this->strSize) ;
            //Destruktor zum löschen des freigegebenen Speichers wird aufgerufen
            delete[] strPtr;
            //Speicher mit erhöhter Kapazität wird angefordert
            this->strPtr = new char[sizeof(char)*(c+1)];
            //Gesicherter String auf neuen Speicher übertragen und "\0" wird eingefügt
            strncpy(this->strPtr, temp, this->strSize);
            /*this->strPtr[c+1] = '\0';*/
            //temp wird wieder gelöscht
            delete[] temp;

    }
    //Gibt den C-String zurück
    const char*  MyString::c_str(){

        return strPtr;
    }
    //gibt größe des Strings ohne abhließendes 0-Zeichen zurück
    unsigned int MyString::size(){
        return this->strSize;

    }
    //Leert den String
    void MyString::clear(){
        for (int i = 0; i < this->strCapacity; i++) {
            this->strPtr[i] = 0;
        }

    }
    //Hängt Strings aneinander
    MyString & MyString::append(MyString &str){
        // Ermittelt Größe des neuen Strings
        unsigned int newSize = this->strSize+str.strSize;
        //Größe und Kapazität des Strings werden aktualisiert
        this->strSize = newSize;
        this->strCapacity = newSize;
        //vergrößert den Speicher für den neuen String
        this->reserve(newSize);
        //Fügt die Strings zusammen 
        strcat(this->strPtr,str.strPtr);
        //abschließendes 0-Zeichen
        this->strPtr[this->strSize] = '\0';
        return str;
    }
    //Überschreibt String mit neuen Chars
    MyString & MyString::assign(MyString &str){
        //prüft ob neuer Speicher beschafft werden soll 
        if (this->strSize < str.strSize){
            reserve(str.strSize);
            //fügt neuen String ein
            strncpy(this->strPtr, str.strPtr,str.strSize);
            //aktualisiert Größe und Kapazität des Strings
            this->strSize = str.size();
            this->strCapacity = str.capacity();
            //abschließendes 0-Zeichen
            this->strPtr[this->strSize] = '\0';
        }
        else{
            //falls Speicher nicht vergrößert werden muss 
            //wird string eingefügt
            strncpy(this->strPtr, str.strPtr, str.strSize);
        }
        return str;
    }
    //Gibt Kapazität zurück
    unsigned int MyString::capacity(){
        return this->strCapacity;
    }
    //prüft ob String leer ist 
    bool MyString::empty(){
        if (this->strSize = 0)
            return true;
    }
    //ersetzt Zeichen an der i-ten Stelle
    char &MyString::at( int i){
        if (i > this->strCapacity)
            return this->strPtr[0];
        else{
            return this->strPtr[i-1];
        }
    }

    //Hausaufgabe 3 Eigene String Klasse Teil 2 Operatoren

    MyString MyString::operator+( MyString & other){

        MyString neu(this->strPtr);

        neu.append(other);
        return neu;
    }
    bool  MyString::operator==(const MyString & compare){
        if (this->strSize == compare.strSize){
            for (int i = 0; (this->strPtr[i] && compare.strPtr[i]) != '\0'; i++){
                if (this->strPtr[i] != compare.strPtr[i]){
                    return 0;
                    break;
                }
                else return 1;


            }

        }

    }
    ostream &operator<< (ostream & push, MyString out){ 
        /*for (int i = 0; out.strPtr[i] != '\0'; i++){
            push << out.strPtr[i];
        }*/

        push << out.c_str();
        return push;

    }

    MyString  MyString::operator=(MyString & change){


        this->assign(change);
        return change;
    }

    //MyString  MyString::operator[](MyString & index){
    //
    //}

下面是我将使用 mystring 类的程序

标题:

#include"..\A3\A3\MyString.hpp"
#pragma once
class Fahrzeug{

private:
    MyString kz;
    /*static int vin;*/
    double km;
public:
    Fahrzeug( char *kfz);
    void fahren(double);
    /*friend ostream & operator<<(ostream &, Fahrzeug);*/
};

cpp 文件:

#include "Fahrzeug.hpp"
#include"..\A3\A3\MyString.hpp"
#pragma once

Fahrzeug::Fahrzeug(char* kfz)
:kz(kfz)
{

}

void Fahrzeug::fahren(double km)
{

    this->km += km;
}
//ostream &operator<<(ostream& push, Fahrzeug out){
//  return push<<"KennZeichen: "<<out.kz<<endl<<"VIN: "/*<<out.vin*/<<endl<<"KM: "<<out.km<<endl;
//}

主程序:

#include "Fahrzeug.hpp"

#pragma once
#include <iostream>
using namespace std;

//int Fahrzeug::zaehler = 0;

int main() {
    Fahrzeug f1("ES - H 123");
    /*cout << f1 << endl;*/
    f1.fahren(101.5);
    /*cout << f1 << endl;*/
    Fahrzeug f2("ES - M 4711");
    f2.fahren(10.57);
    /*cout << f2 << endl;*/
    return 0;
}

【问题讨论】:

  • 请向我们展示您的MyString 类的标题(它的声明)。您描述为 header 文件的代码与您描述为 .cpp 文件的代码相同
  • 我怀疑链接器没有看到 MyString 的目标文件。检查您的构建命令/脚本以确保 MyString.obj 包含在链接命令中。另请注意,您似乎已在 MyString 的 .cpp 中粘贴了两次——一次代替了 MyString 标头。
  • 您可能不应该在 .cpp 文件中包含 #pragma once,但这不是导致此问题的原因。

标签: c++ linker


【解决方案1】:

这是一个链接错误。这意味着编译器可以找到函数的原型,但找不到函数的实际定义。

在您的特定情况下,通过在 Fahrezug 类中创建 kz 变量,您调用了 MyString 类的构造函数,由于某种原因链接器找不到其定义。我的猜测是,这是因为字符串类的头文件和字符串类的源文件是相同的,所以链接器两次看到构造函数的定义并且不知道使用哪一个(即使两者相同,链接器不会检查,当它看到同一个函数的两个定义时,它会给你一个错误而无需进一步查看)。

如果您不小心粘贴了源代码而不是标头,则问题可能是您忘记在项目中包含源文件(源文件需要在 IDE 中的源文件列表中)。

我也推荐使用

#ifndef MYHEADER_H
#define MYHEADER_H

在每个头文件的开头和末尾#endif 以避免包含两次相同的头文件并因此出现此类错误。

【讨论】:

  • 我不认为 MyString 的头文件和源文件是相同的。我认为 OP 无意中粘贴了标题而不是源。您将其称为链接器错误是正确的,但随后您谈论的是编译器而不是链接器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-28
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多