如何在源文件中定义一个类并在头文件中声明它(不必使用`class :: method`语法定义类方法)?

时间:2017-09-23 03:07:18

标签: c++ class header-files declaration one-definition-rule

我正在查看其中一个头文件中包含以下内容的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来定义类?

2 个答案:

答案 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 ++最佳实践定义类的方式。