0

我有一个带有一些类代码的 .h 文件 - overlay.h

    #include<iostream>
    #include<boost/thread.hpp> 
    #include<vector>
    #include<boost/asio.hpp> 
    #include <string>
    #include <boost/serialization/vector.hpp>
    #include <boost/archive/text_oarchive.hpp> 
    #include <boost/archive/text_iarchive.hpp> 
    #include <sstream> 
    #include <boost/tuple/tuple.hpp>
    #include<member.h>
    using boost::asio::ip::tcp;

    class overlay_server{...};

struct member{
    std::string ip_address;
    short int port;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & ip_address;
        ar & port;
    }
};

现在我将结构移动到另一个名为 member.h 的新文件中并包含该文件,以便我的类 overlay_server 可以使用它。现在,当我构建程序时,我得到了错误。

我应该进行哪些更改才能完成这项工作?我在 SO 上阅读了有关标头保护的信息,但无法真正理解如何在这里实现它来解决问题。

- - 编辑 - -

成员.h

struct member{
    std::string ip_address;
    short int port;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & ip_address;
        ar & port;
    }
};

运行.cpp

    #include<overlay_server.h>
#include<overlay_client.h>

int main(){

    overlay_server overlay_server_(8002);
    boost::thread thread_(boost::bind(&overlay_server::member_list_server, overlay_server_));


    overlay_client overlay_client_("127.0.0.1",8002);
    overlay_client_.member_list_client();

    thread_.join();
}

我没有在任何地方重新定义结构。我有另一个名为 overlay_client 的类,它也使用 struct 成员。

在我的主要功能中,我创建了overlay_server 和overlay_client 的对象。现在我的程序只有当 member.h 包含在 overlay_server.h 中时才运行(尽管 overlay_server 和 overly_client 中的代码都需要它)如果它包含在两者中,那么我会收到重新定义错误

为什么?

- - 编辑 - -

我的 member.h 中的这段代码解决了 编译错误“'struct' type redefinition”的问题,尽管它是它的第一个定义

4

3 回答 3

1

这就是正在发生的事情。你有

member.h

包含在overlay_server.hoverlay_client.h

现在当你在 main.cpp 中包含这两个

就像您在 main.cpp 中执行此操作一样(实际上预处理器扩展如下)

#include"member.h"
#include"member.h"

所以通常在完全扩展后会是这样

struct member{...};
struct member{...};    //redifinition!!

所以编译器将其解析为两个定义struct member(因为它会访问 member.h 两次并读取成员结构的 def)。

怎么做才能避免这种情况

在 member.h 添加这个

#ifndef MEMBER_DECL    //initially not defined
#define MEMBER_DECL    //include guard(now first time you enter this MEMBER_DECL will get defined. so second time compiler comes here it skips this.)
struct member
{
 //rest here
};

#endif

现在主要你将拥有这个

#include"member.h" //when this happens MEMBER_DECL is defined

所以

//#include"member.h" member will not be expanded again hence resolving your redfinition 
于 2013-05-24T04:33:47.420 回答
1

您也可以使用 apragma并获得相同的效果。在所有头文件的顶部,写:

#pragma once

rest of the header
 .
 .
 .

使用包含保护的方法是用包含保护将头文件中的所有内容包围起来,如下所示:

// At the very top
#if !defined(SOME_SYMBOL)
#define SOME_SYMBOL

rest of the header
 .
 .
 .

// At the very bottom
#endif  // SOME_SYMBOL

现在,选择一个合理的名称而不是SOME_SYMBOL非常重要。大多数程序员根据文件名(以及路径和项目名称以及公司/个人名称)创建保护名称。例如,对于位于“[项目根目录”中的名为“some_header.h”(或“SomeHeader.h”)的头文件]/include/myproject",您可以将守卫名称命名为__INCLUDE__MY_PROJECT__SOME_HEADER_H__. 但这只是一个建议;任何独特的符号都可以。

您还可以结合使用pragma和包含保护(因为该pragma方法可以改善非常大的项目中的编译时间,但并非所有编译器都支持它。)如果你想要它们,你会写:

#pragma once

#if !defined(__INCLUDE__MY_PROJECT__SOME_HEADER_H__)
#define __INCLUDE__MY_PROJECT__SOME_HEADER_H__

rest of the header
 .
 .
 .

#endif  // __INCLUDE__MY_PROJECT__SOME_HEADER_H__

这没有负面影响(据我所知),只有防止构建错误和使构建更快(在大型项目上)的潜力。但请注意,包括警卫的含义#pragma once并不完全相同。在非常罕见的情况下,您需要使用其中一种,或者两者都不使用。

于 2013-05-24T04:30:04.310 回答
0

如果overlay.h包含struct member定义并且member.h也有struct member定义,则不能包含member.hfrom overlay.h。以下是包含警卫的工作方式:

        #include<iostream>
        #include<boost/thread.hpp> 
        #include<vector>
        #include<boost/asio.hpp> 
        #include <string>
        #include <boost/serialization/vector.hpp>
        #include <boost/archive/text_oarchive.hpp> 
        #include <boost/archive/text_iarchive.hpp> 
        #include <sstream> 
        #include <boost/tuple/tuple.hpp>
        #include<member.h>
   #ifndef _H__MEMBER_
   #define _H__MEMBER_
        using boost::asio::ip::tcp;
        class overlay_server{...};

    struct member{
        std::string ip_address;
        short int port;

        template<class Archive>
        void serialize(Archive & ar, const unsigned int version)
        {
            ar & ip_address;
            ar & port;
        }
    };
#endif

注意 #ifndef _H__MEMBER_and#define _H__MEMBER_#endif。使用包含守卫,它确保您的标头只包含一次,因为在第一次包含后,H _MEMBER_ 将已经定义,因此它将跳过定义。您的命名约定可能会有所不同,但通常我会_H__<HEADER NAME>_按照我的定义做一些事情。

于 2013-05-24T04:07:21.487 回答