【问题标题】:multiple definitions error in c++ and solution to solve this issuec++中的多个定义错误以及解决此问题的解决方案
【发布时间】:2013-09-20 10:07:41
【问题描述】:

我是 C++ 新手。我对 C++ 中的多重定义错误有一些疑问。

假设我在一个程序中有 3 个文件。 1 个头文件和 2 个 .cpp 文件。我在两个 .cpp 文件中都包含了头文件。

  1. 我已经在头文件中声明了一个类,并以完全相同的方式在每个 .cpp 文件中定义了该类。那么这种类型的实现会不会导致多重定义错误呢?如果是这样,是不是因为它有两个类定义副本,而编译器在链接两个 .o 文件时不知道该取哪一个?

我们可以通过在头文件中使用extern并仅在其中一个文件中定义类来解决这个问题吗?如果我们可以通过使用这种方法解决问题,我们是否必须包含.cpp(带有类定义) 到其他 .cpp 文件中(没有类定义)?

  1. 我已经在头文件中声明并定义了一个类。这种情况和上面(1中提到的)一样吗?

  2. 我在头文件中声明了一个类,并在每个 .cpp 文件中定义了该类,但定义(函数体)不同。那么这种类型的实现会导致多重定义错误吗?如果是这样,我们如何解决.cpp文件中函数体不同的问题?

【问题讨论】:

    标签: c++ compiler-errors linkage multiple-definition-error


    【解决方案1】:

    1) 您只需在一个 cpp 文件中“定义类”即可解决此问题。为什么要在两个文件中定义它?

    2) 不要在头文件中定义东西,只声明它们。此规则有例外,例如内联函数。类本身也可以定义不止一次(我的意思是声明类的方法和数据成员,(即写class XYZ { ... };)但每个定义必须相同。实现这一点的最简单方法是定义一个类一次一个头文件。那么在多个位置包含该头文件所产生的每个定义都必然是相同的。

    3) 这个更傻,定义某事两次是一回事,但定义两次而且每次都不同,就更没有意义了。

    我想问题是为什么您认为有时可能需要多次定义事物。不要那样做。

    您还应该明确“定义类”的含义。我认为这意味着定义类的方法和静态成员。但是,如果您有其他想法,那可能会造成混乱。像往常一样,避免这种术语混淆的最好方法是发布一些代码。

    【讨论】:

    • 好吧,类定义 is 通常放在标题中,尽管标准要求它在每个翻译单元中都相同。您所说的几乎适用于每个(非内联)函数的定义,但不适用于类本身。
    • @Agentlien 我不确定 OP 的“定义类”是什么意思。正如我在回答中所说,我认为他的意思是定义类的方法。
    • 加读了一段时间,我相信他的意思是类定义。他是否意识到这与定义成员函数之间的区别,我不能说。但是,您的回答清楚地表明(用相当严厉的话),您不应该在头文件中定义一个类,这是不正确的。
    • @Agentlien '相当苛刻的话' 我感到沮丧,让我感到沮丧的事情之一是人们在询问有关他们的代码的问题时不愿意发布代码。
    • 我明白你的意思。我同意这个问题有点太模糊了。不过,我的意思是,如果有人在简要查看问题后会阅读您的答案,那么您清楚地说明不应在头文件中定义类。事实并非如此,所以我建议尝试重新表述一下?
    【解决方案2】:

    要回答所有这些问题,您只需要查看声明和定义的目的。

    类的声明只是说明该类存在以及在哪个上下文中。对于一个类,简单的前向声明(例如class Banana;)允许您使用指向该类的指针或引用,仅此而已。

    定义准确地说明了类是什么。也就是说,它有哪些成员以及它从哪些基类派生而来。每当您访问该类的成员或需要知道其实例的大小时,您都需要它可用。这意味着需要将类定义放在头文件中,以便可以将其包含在使用该类的所有文件中的任何位置。这没关系,因为标准规定一个类可以在多个翻译单元中定义,只要所有定义都相同。

    类定义通常如下所示:

    class Banana
    {
    public: 
      Banana(){}
    
      void eat();
    
    private:
      //....
    };
    

    但是请注意,这个类的定义仅仅意味着类本身的定义,而不是非内联的成员函数。比如上面例子中的void eat()。这些需要在 .cpp 文件中定义,因为它们可能不会在多个翻译单元中定义。

    简而言之:

    1. 这样不对,只在头文件中定义,在匹配的.cpp文件中定义非内联成员函数。切勿定义相同的函数或输入多个文件。
    2. 这样就可以了,只要在.cpp文件中单独定义成员函数即可。
    3. 不,见 1。

    【讨论】:

      【解决方案3】:

      1) 您的项目中不能有同一个类的两个定义。而且我不知道你打算如何使用它。如果您想创建具有不同行为的一个类的实例,请使用如下虚函数:

      class A {
      public:
          virtual int foo() = 0;
      }
      
      class B : public A {
      public:
          virtual int foo() { return 1; }
      }
      
      class C : public A {
      public:
          virtual int foo() { return 2; }
      }
      

      2) 你可以在头文件中定义类(java-style),但这不是最好的主意,因为编译器会消耗更多的资源来构建其他文件,包括这个头文件。让编译器快速工作 - 在 .cpp 文件中定义类。

      3) 见第 1 页

      【讨论】:

        【解决方案4】:

        在多个地方定义一个类没有问题。当您将定义放在一个标头中并将#include 该标头放在多个源文件中时,就会发生这种情况。但是,请注意,定义类意味着写出类包含的内容,而不是定义其成员。这是一个类定义:

        class C {
            void f();     // member function declaration
            void g() { }  // member function declaration with inline definition
            int i;        // member declaration
            static int j; // member declaration
        };
        

        像大多数事情一样,您不能在一个源文件中多次定义它。但是,它可以出现在任意数量的源文件中,只要它在任何地方都相同。

        这个类定义声明了两个必须在某处定义的成员,通常像这样:

        void C::f() {
            std::cout << "In C::f\n";
        }
        
        int C::j = 3;
        

        这些定义在整个程序中只能出现一次;通常每个都在源文件中定义一次。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多