Есть «проблемы» с тем, как вы использовали спецификатор inline
. Исправление заключается в том, чтобы просто удалить спецификатор inline
из всех определений метода String
, чтобы устранить ошибку go.
Давайте разберемся, почему ваша программа некорректна.
Я буду использовать точки из встроенного спецификатора cppreference :
Встроенная функция или встроенная переменная (начиная с C ++ 17) имеет следующие свойства:
- Определение встроенной функции или переменной (начиная с C ++ 17) должно быть доступно в единице перевода, к которой к ней осуществляется доступ (необязательно до точки доступа).
- Встроенная функция или Переменная (начиная с C ++ 17) с внешней связью (например, не объявлено stati c) имеет следующие дополнительные свойства:
- Может быть несколько определений встроенной функции или переменной (начиная с C ++ 17) в программе, если каждое определение отображается в разных единицах перевода и (для не встроенных c встроенных функций и переменных (начиная с C ++ 17)) все определения идентичны. Например, встроенная функция или встроенная переменная (начиная с C ++ 17) могут быть определены в заголовочном файле, который # include'd в нескольких исходных файлах.
- Он должен быть объявлен встроенным в каждой единице перевода ,
- Он имеет одинаковый адрес в каждой единице перевода.
Объявление 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
, поэтому вы также можете переместить определение функции в определение класса.