c++ - 如何解决对我自己的类的构造函数和析构函数的未定义引用的问题?
问题描述
我写了一个简单的程序,它使用一个带有构造函数、析构函数和数据成员的类。当我尝试初始化一个对象时,调试器告诉我没有析构函数和析构函数。我在Clion,VS2019和VSCode中尝试过。我得到了与 4) 相同的结果。我不知道它在我实际创建构造函数和析构函数时一直发生。
请帮助我。谢谢!
1) 字符串.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) 字符串.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
解决方案
您使用说明符的方式存在“问题” inline
。修复只是inline
从所有String
方法定义中删除说明符以使错误消失。
让我们深入研究为什么您的程序格式错误。
我将使用cppreference 内联说明符中的点:
内联函数或内联变量 (C++17 起) 具有以下属性:
- 内联函数或变量的定义(C++17 起)必须在访问它的翻译单元中是可访问的(不一定在访问点之前)。
- 具有外部链接(例如未声明为静态)的内联函数或变量(C++17 起)具有以下附加属性:
- 程序中可能有多个内联函数或变量的定义(C++17 起),只要每个定义出现在不同的翻译单元中,并且(对于非静态内联函数和变量(C++17 起) )) 所有定义都是相同的。例如,内联函数或内联变量 (C++17 起) 可以在多个源文件中 #include 的头文件中定义。
- 它必须在每个翻译单元中声明为内联。
- 它在每个翻译单元中具有相同的地址。
广告 1)简单来说:如果你有一个像inline String::String(const char *cstr) { something }
你这样的内联函数定义,你可以从同一个.cpp
文件中调用它。如果您从其他.cpp
文件中调用它,例如您在 in 中定义了函数String.cpp
但从 中调用它main.cpp
,那是无效的。
广告 2)您的函数不是静态的,因此本节适用。
广告 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
,因此您也可以在类定义中移动函数定义。
推荐阅读
- python - 如何制作 django 临时列表?
- oracle - 在一个过程中调用多个过程
- c# - 如何根据参数将数据插入到两个表中
- javascript - 是否可以检测何时在 JavaScript 中创建 ES6 类的第一个实例?
- selenium - 硒按钮单击python
- python - 如何使用 Python 发出 URL 请求并返回重定向到的 URL?
- prolog - 如何在 ECLIPSE-CLP 或 Prolog 中实现这些 Sigma 符号
- electron - 如何将电子生成器与目标便携式设备一起使用?
- python - 打印语句的问题
- vb.net - 如何在 vb.net 的查询字符串中不通过 $expand 来扩展(odata-webapi)所有属性