简体   繁体   中英

Helper understanding linker error LNK2019

I know there are a lot questions here about this topic, but I can't find the unreferenced symbol in my code.

This is the error:

error LNK2019: unresolved external symbol "public: __thiscall MyString::MyString(char const *)" (??0MyString@@QAE@PBD@Z) referenced in function "public: __thiscall Fahrzeug::Fahrzeug(char *)" (??0Fahrzeug@@QAE@PAD@Z)

This is the header for the string class created:

#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

This is the cpp file for mystring class

    #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){
    //
    //}

and here comes the program on which i will use the mystring class

Header:

#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 file:

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

main program:

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

That's a linking error. That means that the compiler could find the prototype of the function but that it couldn't find the function's actual definition.

In your specific case, by creating the kz variable in the Fahrezug class, you called the constructor for the MyString class which for some reason the linker couldn't find the definition of. My guess is that that's because the header for the string class and the source file for the string class are identical so the linker sees the definition of the constructor twice and doesn't know which one to use (even if the two are identical, the linker doesn't check that, when it sees two definitions for the same function, it gives you an error without looking any further).

If you pasted the source instead of the header by accident, maybe the problem is that you forgot to include your source file in the project (the source file needs to be in the list of source files in your IDE).

I also recommend using

#ifndef MYHEADER_H
#define MYHEADER_H

at the beginning of each header file and #endif at the end to avoid including twice the same header file and therefore getting this type of error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM