多重定义:在 link 时间出错
multiple definition: error at link time
我正在写一些 classes 用于 C++ 入门书中关于复制控制成员的练习。
我将 classes 定义放在它们各自的 header 文件中,并在代码文件中实现。我似乎已经做了所有应该做的事情,但是我在link时出错我无法理解(我已经花了半个小时思考它)
这是消息 class(headers 和代码文件)
message.h
#include <string>
#include "folder.h"
class message {
friend void swap(message&,message&);
public:
explicit
message(const std::string& =std::string());
// copy control
message(const message&);
~message();
message &operator=(const message&);
// interface
void save(folder&);
void remove(folder&);
private:
// data members
std::string text;
std::set<folder*> folders;
// utility functions
void add_to_folders(const message&);
void remove_from_folders();
};
void swap(message &m1,message &m2)
{
swap(m1.text,m2.text);
swap(m1.folders,m2.folders);
}
message.cpp
#include "message.h"
message::message(const std::string &t) : text(t) {}
message::message(const message &other) : text(other.text),folders(other.folders)
{
add_to_folders(other);
}
message::~message()
{
remove_from_folders();
}
message& message::operator=(const message &other)
{
remove_from_folders();
text=other.text;
folders=other.folders;
add_to_folders(other);
return *this;
}
void message::save(folder &f)
{
folders.insert(&f);
f.addMsg(this);
}
void message::remove(folder &f)
{
folders.erase(&f);
f.remMsg(this);
}
void message::add_to_folders(const message& m)
{
for (auto i:m.folders)
i->addMsg(this);
}
void message::remove_from_folders()
{
for (auto i:folders)
i->remMsg(this);
folders.clear();
}
这是文件夹 class
folder.h
#include <set>
class message;
class folder {
public:
/*folder();
folder(const folder&);
~folder();
folder &operator=(const folder&);*/
void addMsg(message*);
void remMsg(message*);
private:
std::set<message*> messages;
};
folder.cpp
#include "folder.h"
void folder::addMsg(message *m)
{
messages.insert(m);
}
void folder::remMsg(message *m)
{
messages.erase(m);
}
每封邮件都有一个 collection 指向文件夹的指针,反之亦然。每个文件单独编译都很好,但是当我 link 他们三个我得到一个错误,说交换函数(我在消息 class header 中定义)被重新定义。
main.cpp
#include "message.h"
int main()
{
folder f1;
message m1;
}
我做错了什么?
你记得在你的头文件中加入 include guards 吗?
#ifndef __MY_HEADER__
#define __MY_HEADER__
...
#endif
或者如果您习惯使用 C++ 标准之外的功能:
#pragma once
...
您在 message.cpp
和 main.cpp
中都包含了头文件 message.h
。因为你有:
void swap(message &m1,message &m2)
{
swap(m1.text,m2.text);
swap(m1.folders,m2.folders);
}
在 message.h
中,您现在在 main.cpp
翻译单元和 message.cpp
翻译单元中都声明了交换函数。这将导致多重定义错误。您需要将 swap()
移动到 message.cpp
您的问题的解决方案非常简单:您在消息中将 void swap( data1, data2 ) 声明为友元函数 class 然后在 *.h 文件的底部定义它。从 *.h 文件中取出实现并将其放入 message.cpp 文件中的任何 classes 函数之前。确保在 *.cpp 文件中 classe 的构造函数之前有定义(实现),因为您的 class 对象将依赖于此交换函数。这应该可以解决您在构建过程中的问题。是的,这 3 个文件中的每一个都将成功编译,但解决方案将无法构建,因为它无法解析此方法,因为您已在 *.h 文件中定义了它。此外,您在 folder.h 文件中使用了 class 原型消息,您还应该在 folder.cpp 文件中包含 #include "message.h",但这需要您拥有 *带有 #ifndef ... #define ... #endif 指令的 .h 文件。这应该对你有帮助!
我正在写一些 classes 用于 C++ 入门书中关于复制控制成员的练习。
我将 classes 定义放在它们各自的 header 文件中,并在代码文件中实现。我似乎已经做了所有应该做的事情,但是我在link时出错我无法理解(我已经花了半个小时思考它)
这是消息 class(headers 和代码文件)
message.h
#include <string>
#include "folder.h"
class message {
friend void swap(message&,message&);
public:
explicit
message(const std::string& =std::string());
// copy control
message(const message&);
~message();
message &operator=(const message&);
// interface
void save(folder&);
void remove(folder&);
private:
// data members
std::string text;
std::set<folder*> folders;
// utility functions
void add_to_folders(const message&);
void remove_from_folders();
};
void swap(message &m1,message &m2)
{
swap(m1.text,m2.text);
swap(m1.folders,m2.folders);
}
message.cpp
#include "message.h"
message::message(const std::string &t) : text(t) {}
message::message(const message &other) : text(other.text),folders(other.folders)
{
add_to_folders(other);
}
message::~message()
{
remove_from_folders();
}
message& message::operator=(const message &other)
{
remove_from_folders();
text=other.text;
folders=other.folders;
add_to_folders(other);
return *this;
}
void message::save(folder &f)
{
folders.insert(&f);
f.addMsg(this);
}
void message::remove(folder &f)
{
folders.erase(&f);
f.remMsg(this);
}
void message::add_to_folders(const message& m)
{
for (auto i:m.folders)
i->addMsg(this);
}
void message::remove_from_folders()
{
for (auto i:folders)
i->remMsg(this);
folders.clear();
}
这是文件夹 class
folder.h
#include <set>
class message;
class folder {
public:
/*folder();
folder(const folder&);
~folder();
folder &operator=(const folder&);*/
void addMsg(message*);
void remMsg(message*);
private:
std::set<message*> messages;
};
folder.cpp
#include "folder.h"
void folder::addMsg(message *m)
{
messages.insert(m);
}
void folder::remMsg(message *m)
{
messages.erase(m);
}
每封邮件都有一个 collection 指向文件夹的指针,反之亦然。每个文件单独编译都很好,但是当我 link 他们三个我得到一个错误,说交换函数(我在消息 class header 中定义)被重新定义。
main.cpp
#include "message.h"
int main()
{
folder f1;
message m1;
}
我做错了什么?
你记得在你的头文件中加入 include guards 吗?
#ifndef __MY_HEADER__
#define __MY_HEADER__
...
#endif
或者如果您习惯使用 C++ 标准之外的功能:
#pragma once
...
您在 message.cpp
和 main.cpp
中都包含了头文件 message.h
。因为你有:
void swap(message &m1,message &m2)
{
swap(m1.text,m2.text);
swap(m1.folders,m2.folders);
}
在 message.h
中,您现在在 main.cpp
翻译单元和 message.cpp
翻译单元中都声明了交换函数。这将导致多重定义错误。您需要将 swap()
移动到 message.cpp
您的问题的解决方案非常简单:您在消息中将 void swap( data1, data2 ) 声明为友元函数 class 然后在 *.h 文件的底部定义它。从 *.h 文件中取出实现并将其放入 message.cpp 文件中的任何 classes 函数之前。确保在 *.cpp 文件中 classe 的构造函数之前有定义(实现),因为您的 class 对象将依赖于此交换函数。这应该可以解决您在构建过程中的问题。是的,这 3 个文件中的每一个都将成功编译,但解决方案将无法构建,因为它无法解析此方法,因为您已在 *.h 文件中定义了它。此外,您在 folder.h 文件中使用了 class 原型消息,您还应该在 folder.cpp 文件中包含 #include "message.h",但这需要您拥有 *带有 #ifndef ... #define ... #endif 指令的 .h 文件。这应该对你有帮助!