对成员函数的未定义引用

DkS*_*kSw 5 c++ g++

我正在尝试解决有关外部定义的构造函数的编译问题。

这是有这个问题的 2 个类:

//Username.h

#ifndef USERNAME_H
#define USERNAME_H

#include <string>
using namespace std;

class Username{
private:
    string Name;
public:
    Username(string = "");
    string getName() const;
    void setName(string);
};

#endif
Run Code Online (Sandbox Code Playgroud)

...

//Username.cpp

#include "Username.h"

Username::Username(string n):Name(n){}
string Username::getName() const{return Name;}
void Username::setName(string n){Name = n;}
Run Code Online (Sandbox Code Playgroud)

...

//User.h

#ifndef USER_H
#define USER_H

#include <string>
#include "Username.h"
using namespace std;

class User{
protected:
        Username* UserUsername;
public:
    User(string s);
    virtual ~User();
    Username* getUsername() const;
    void setUsername(Username*);
};

#endif
Run Code Online (Sandbox Code Playgroud)

...

//User.cpp

#include "User.h"

User::User(string s):UserUsername(new Username(s)){}

User::~User(){}

Username* User::getUsername() const{return UserUsername;}

void User::setUsername(Username* u){UserUsername=u;}

int main(){return 0;}
Run Code Online (Sandbox Code Playgroud)

如果我使用“g++ User.cpp”进行编译,则会出现此错误:

/tmp/ccEmWmfl.o: In function `User::User(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':

User.cpp:(.text+0x3e): undefined reference to `Username::Username(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'

collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

如果我使用“g++ User.cpp Username.cpp -o main”或者如果我使用内联构造函数/析构函数,我不会出错。

这些类非常简单,但我还有很多需要编译的类需要不止一个类。

我是用 g++ 在 Ubuntu shell 中编译的新手,所以请有人帮我理解吗?

Dou*_* T. 4

g++ 用户.cpp

这会编译 User.cpp 并尝试从中创建可执行文件(即调用链接器)。由于 User.cpp 有一个未在 User.cpp 中完全定义的符号(此处的 Username 构造函数:

User::User(string s):UserUsername(new Username(s)){}
Run Code Online (Sandbox Code Playgroud)

该符号预计在链接阶段定义。链接是通过组合您生成的所有 cpp 的所有生成的目标文件输出并将缺少的符号拼凑在一起来完成的。在这里,您没有告诉 g++ 除了带有 main 的 cpp 之外在哪里可以找到 Username 构造函数的完整定义,因此它失败了。

然而,这:

g++ User.cpp 用户名.cpp -o main

告诉链接器在哪里可以找到完整的用户名定义(在编译 Username.cpp 生成的目标文件中)。因此,链接可以通过使用 Username.cpp 中定义的内容来匹配 User.cpp 中未定义的标识符来成功填充缺失的部分。

您可能会想——“好吧,我已经通过包含头文件告诉编译器了,它应该知道!”。你所做的就是声明符号。您已做出承诺,最终会定义某些内容,无论是在编译该 cpp 期间,还是稍后将其与编译另一个 cpp 生成的另一个目标文件链接起来。g++ 需要知道您打算从哪里提取所有定义,以便它可以正确构建最终的可执行文件。