Как я могу решить проблему с неопределенной ссылкой на конструктор и функцию деструктора моего собственного класса? - PullRequest
0 голосов
/ 27 января 2020

Я написал простую программу, которая использует класс с конструктором, деструктором и членом данных. Когда я попытался инициализировать объект, отладчик сказал мне, что нет деструктора и деструктора. Я попробовал это в Clion, VS2019 и VSCode. И я получил такой же результат, как 4). Я не знаю, это происходит все время, когда я на самом деле создал конструктор и деструктор.

Пожалуйста, помогите мне. СПАСИБО!

1) String.h

#ifndef TEST_STRING_H
#define TEST_STRING_H

class String {
  public:
    explicit String(const char *cstr = nullptr);

    String(const String &str);

    String &operator=(const String &str);

    ~String();

    char *get_c_str() const { return m_data; }

  private:
    char *m_data;
};

#endif // TEST_STRING_H

2) String. cpp

#include "String.h"
#include <cstring>

inline String::String(const char *cstr) {
    if (cstr) {
        m_data = new char[strlen(cstr) + 1];
        strcpy(m_data, cstr);
    } else {
        m_data = new char[1];
        *m_data = '\0';
    }
}

inline String::~String() { delete[] m_data; }

inline String &String::operator=(const String &str) {
    if (this == &str)
        return *this;

    delete[] m_data;
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data, str.m_data);
    return *this;
}

inline String::String(const String &str) {
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data, str.m_data);
}

3) main. cpp

#include <iostream>
#include "String.h"

using namespace std;

int main() {
    String s1("hello");
    return 0;
}

4) Результат

/tmp/ccCIK0hs.o: In function `main':
/home/Projects/test/main.cpp:7: undefined reference to `String::String(char const*)'
/home/Projects/test/main.cpp:7: undefined reference to `String::~String()'
collect2: error: ld returned 1 exit status

1 Ответ

0 голосов
/ 27 января 2020

Есть «проблемы» с тем, как вы использовали спецификатор inline. Исправление заключается в том, чтобы просто удалить спецификатор inline из всех определений метода String, чтобы устранить ошибку go.

Давайте разберемся, почему ваша программа некорректна.

Я буду использовать точки из встроенного спецификатора cppreference :

Встроенная функция или встроенная переменная (начиная с C ++ 17) имеет следующие свойства:

  1. Определение встроенной функции или переменной (начиная с C ++ 17) должно быть доступно в единице перевода, к которой к ней осуществляется доступ (необязательно до точки доступа).
  2. Встроенная функция или Переменная (начиная с C ++ 17) с внешней связью (например, не объявлено stati c) имеет следующие дополнительные свойства:
    1. Может быть несколько определений встроенной функции или переменной (начиная с C ++ 17) в программе, если каждое определение отображается в разных единицах перевода и (для не встроенных c встроенных функций и переменных (начиная с C ++ 17)) все определения идентичны. Например, встроенная функция или встроенная переменная (начиная с C ++ 17) могут быть определены в заголовочном файле, который # include'd в нескольких исходных файлах.
    2. Он должен быть объявлен встроенным в каждой единице перевода ,
    3. Он имеет одинаковый адрес в каждой единице перевода.

Объявление 1) Простыми словами: если у вас есть определение встроенной функции, например inline String::String(const char *cstr) { something }, вы можете вызывать ее из того же файла .cpp. Если вы вызываете его из другого .cpp файла, как вы определили функцию в String.cpp, но вызываете ее из main.cpp, это недопустимо.

Ad 2) Ваши функции не устарели c, так что это применяется раздел.

Объявление 2.1) Если у вас inline String::String(const char *cstr) в вашем String.cpp, вы должны иметь inline String::String(const char *cstr); в объявлении класса в String.h. Если вы объявляете это с inline, оно должно быть inline везде, в том числе String.h. Прямо сейчас в вашем коде, в String.h он не имеет inline.

Исправление - придерживаться правила в пунктах 1 и 2.1. Поэтому либо удалите ключевое слово inline из String.cpp, и пусть все ваши функции будут обычными функциями с внешней связью, что является обычным способом программирования.

В качестве альтернативы, если вам нужно, чтобы ваши функции были с inline, переместите весь код с String.cpp на String.h и добавьте inline к этим объявлениям функций-членов. Как и в следующем коде:

#ifndef TEST_STRING_H
#define TEST_STRING_H

class String {
  public:
    inline explicit String(const char *cstr = nullptr);
    inline String(const String &str);
    inline String &operator=(const String &str);
    inline ~String();
    inline char *get_c_str() const { return m_data; }
  private:
    char *m_data;
};

#include <cstring>

inline String::String(const char *cstr) {
    if (cstr) {
        m_data = new char[strlen(cstr) + 1];
        strcpy(m_data, cstr);
    } else {
        m_data = new char[1];
        *m_data = '\0';
    }
}

inline String::~String() { delete[] m_data; }

inline String &String::operator=(const String &str) {
    if (this == &str)
        return *this;

    delete[] m_data;
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data, str.m_data);
    return *this;
}

inline String::String(const String &str) {
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data, str.m_data);
}

#endif // TEST_STRING_H

Обратите внимание, что функции, определенные "внутри" определения класса, неявно inline, поэтому вы также можете переместить определение функции в определение класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...