我正在查看其中一个头文件中包含以下内容的library on github:
class Util
{
public:
static void log( const string& message );
static void log( const char* message );
template<typename T>
static inline string toString(T t) { stringstream s; s << t; return s.str(); }
};
以及源文件中的以下内容:
void Util::log( const string& message )
{
const string& logMessage = "[cppWebSockets] " + message;
syslog( LOG_WARNING, "%s", logMessage.c_str( ) );
}
void Util::log( const char* message )
{
log( string( message ) );
}
为什么当我用源代码文件替换上面的内容时,编译器会抱怨&#34;重新定义&#34;?我认为头文件只保存声明,而源文件实际上定义了类?
class Util
{
public:
void Util::log( const string& message )
{
const string& logMessage = "[cppWebSockets] " + message;
syslog( LOG_WARNING, "%s", logMessage.c_str( ) );
}
void Util::log( const char* message )
{
log( string( message ) );
}
}
如何使用上述样式而不是Util::log
来定义类?
答案 0 :(得分:2)
你真正的问题是你误解了类定义是什么。您作为类定义描述的内容不是类定义。
github标头中的类声明实际上是类Util
的定义。在该定义中,还定义了成员函数toString()
(实际上Util::toString()
)。
源文件然后定义该类的两个成员函数(可能包括标题后,尽管您没有显示)。这两个函数定义不是类的定义。
通常的做法实际上就是github库所做的事情,并且你正试图改变。
当您更改它时,您已将类Util
的定义引入源文件中。如果在包含头之后发生这种情况,编译器将看到类Util
的两个定义。这就是你的编译器抱怨定义的原因。
答案 1 :(得分:1)
如果你有像
这样的代码块class Util
{
...
}
你定义这个类。您提供的第一个示例是定义类,声明头文件中的函数。源文件是定义函数。
当您尝试将class Util
行放在带有大括号的源文件中时,编译器会认为您正在定义一个新类。这就是你得到错误的原因。
如果您只是将class Util;
放在一行,那么您将声明该类。类声明告诉您该类存在,但不会告诉您有关该类的任何信息。
如果删除了头文件并将以下内容放在源文件中,它将进行编译,但其他源文件将无法使用该类(因为它们将不再具有为其定义头文件的头文件)。
class Util
{
public:
void log( const string& message )
{
const string& logMessage = "[cppWebSockets] " + message;
syslog( LOG_WARNING, "%s", logMessage.c_str( ) );
}
void log( const char* message )
{
log( string( message ) );
}
}
如果您想让一个类被多个源文件使用,那么您需要在标头中定义该类。然后你也可以在头文件中定义函数(通常由于很多原因而不鼓励),或者你可以使用Util::log
语法在源文件中定义函数(推荐的做法)。
头文件(以及它们需要使用的方式)是关于C和C ++的常见抱怨。这就是为什么较新的语言(如Java和C#)倾向于不使用头文件的原因。但是,您引用的库是按照C ++最佳实践定义类的方式。