【问题标题】:error C2011: 'member' : 'struct' type redefinition on moving a struct to a new header file错误 C2011:“成员”:将结构移动到新头文件时重新定义“结构”类型
【发布时间】:2013-05-24 03:58:08
【问题描述】:

我有一个带有一些类代码的 .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 的类,它也使用结构成员。

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

为什么?

----编辑----

我 member.h 中的这段代码解决了这个问题 Compile error "'struct' type redefinition" although it's the first definition for it

【问题讨论】:

  • 您在重建之前清理过解决方案吗?
  • 你遇到了什么错误?
  • 可能是标题的错误。
  • 您是否弄乱了包含守卫或是否有多个定义?顺便问一下您在哪里定义了类?你正在使用&lt;&gt; 我认为你最好使用"" 自定义标题
  • 我还没有写任何包含守卫

标签: c++ boost


【解决方案1】:

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

#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 的含义是不是 完全一样。在极少数情况下,您可能需要使用其中一种,或者两者都不使用。

【讨论】:

    【解决方案2】:

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

    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 
    

    【讨论】:

      【解决方案3】:

      如果overlay.h 包含struct member 定义并且member.h 也具有struct member 定义,则您不能从overlay.h 中包含member.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_#define _H__MEMBER_#endif。使用包含守卫,它可以确保您的标头仅包含一次,因为在第一次包含后 H_MEMBER_ 将已经定义,因此它将跳过定义。您的命名约定可能会有所不同,但通常我会按照我的定义按照_H__&lt;HEADER NAME&gt;_ 做一些事情。

      【讨论】:

      • 至于你的“为什么?”。您会收到重新定义错误,因为您包含了两次相同的定义。标头守卫可以防止这种情况发生。有时你也可以只放结构成员;例如在 overly_client.h 中,然后在 overlay_client.cpp 中的 #include
      • @Brad 为什么要在 #include 语句之后放置包含防护?有原因吗?据我所知,这只会使构建变慢,因为编译器可能不得不打开那些包含的文件,只会遇到更多的包含保护并关闭文件并留下它们。为什么不把#include 语句放在 include 守卫中?
      • @yzt 你说得很好,我想我只是将保护放在包含以下内容以提高可读性——我总是喜欢将我的包含放在文件的最顶部。放置包含防护装置的位置更多是个人选择。
      • @Brad 我认为将#include 语句放在标头保护之外会对大型项目的编译时间产生可衡量的影响。因此,我认为这不是个人品味和选择的问题。
      猜你喜欢
      • 2016-05-03
      • 2014-11-01
      • 2020-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多