【问题标题】:Multiple definition of a function error, even when using #if guard clauses函数错误的多重定义,即使使用#if 保护子句
【发布时间】:2013-05-06 09:51:00
【问题描述】:

我正在为我的 C++ 项目创建一个包含 aplusb(int, int) 函数的简单 UTIL.h 文件。但是我无法编译,错误消息是关于 `aplusb(int, int)' 的多个定义。您能帮我纠正错误或给我一些提示吗?

我在这里附上我的项目供您详细参考。

文件 UTIL.h

#ifndef UTIL_H_
#define UTIL_H_

int aplusb(int a, int b) {
    return a + b;
}

#endif /* UTIL_H_ */

文件类A.h

#ifndef CLASSA_H_
#define CLASSA_H_

class ClassA {
public:
    ClassA();
    virtual ~ClassA();
private:
    int sum;
};

#endif /* CLASSA_H_ */

文件类A.cpp

#include "ClassA.h"
#include "UTIL.h"

ClassA::ClassA() {
    // TODO Auto-generated constructor stub
    sum = aplusb(3,5);

}

ClassA::~ClassA() {
    // TODO Auto-generated destructor stub
}

文件类B.h

#ifndef CLASSB_H_
#define CLASSB_H_

class ClassB {
public:
    ClassB();
    virtual ~ClassB();
private:
    int sum;
};

#endif /* CLASSB_H_ */

文件类B.cpp

#include "ClassB.h"
#include "UTIL.h"

ClassB::ClassB() {
    // TODO Auto-generated constructor stub
    sum = aplusb(5,6);
}

ClassB::~ClassB() {
    // TODO Auto-generated destructor stub
}

编译错误信息

ClassB.o: In function `aplusb(int, int)':
/home/vtvan/Desktop/workspace/commonfunc/UTIL.h:11: multiple definition of `aplusb(int, int)'
ClassA.o:/home/vtvan/Desktop/workspace/commonfunc/UTIL.h:11: first defined here
collect2: error: ld returned 1 exit status
make: *** [commonfunc] Error 1

【问题讨论】:

    标签: c++


    【解决方案1】:

    第一个变体 - 使用 inline 说明符

    #ifndef UTIL_H_
    #define UTIL_H_
    
    inline int aplusb(int a, int b) {
        return a + b;
    }
    
    #endif /* UTIL_H_ */
    

    第二个变体 - 在.cpp 文件中写入定义。

    【讨论】:

    • 我很好奇为什么第二个变体是“正确的”,而第一个不是。内联这个函数会有什么问题?
    • 但是为什么标题保护在这种情况下不起作用?我认为标头保护会导致代码只执行一次。在这种情况下,这将只创建一次“int aplusb(int,int)”函数定义。我很困惑..
    • @lukasz1985 一份声明。但没有一个定义。
    【解决方案2】:

    您在包含文件中创建了函数 aplusb。这意味着对于您包含它的每个文件,都会创建一个公共函数 aplusb,从而导致名称冲突。

    如果函数应该是内联的,那么标记它。如果函数应该是模板,则将其标记为模板。如果函数应该是你写的那样,把它放在一个 cpp 文件中,然后把原型保存在 h 文件中。

    .h
    #ifndef UTIL_H_
    #define UTIL_H_
    
    int aplusb(int a, int b);
    
    #endif
    
    .cpp
    int aplusb(int a, int b)
    {
        return a+b;
    }
    

    【讨论】:

      【解决方案3】:

      您应该在头文件中声明您的 aplusb 函数,并在 cpp 文件中提供定义。类似的东西

      util.h:

      #ifndef UTIL_H_
      #define UTIL_H_
      
      int aplusb(int, int);
      
      #endif /* UTIL_H_ */
      

      错误消息告诉您,每次包含 util.h 文件时,您都在重新定义函数,这正是您所做的 :-) 这违反了 ODR(一个-definition-rule),它指出(在这种情况下,函数的)定义必须是唯一的。否则编译器将无法在备选方案之间进行选择(即使在这种情况下,它们恰好相等)。

      请注意,模板会使事情复杂化一点(简而言之,因为模板在实例化之前不是定义)。

      【讨论】:

        【解决方案4】:

        头文件并不打算在其中包含实际功能(某些 C++ 方面,例如模板无法承受)。在您的情况下,一般做法是将您的 UTIL.H 更改为仅对函数进行原型设计 (int aplusb(int a, int b);) 并将其实现移至源文件。

        【讨论】:

        • 将函数放在头文件中是完全可以的,只要将它们标记为内联即可。
        • 我的声明例如模板无法承受并不是要详尽无遗地列出可以将函数放在头文件中的所有情况。
        • 但碰巧模板与手头的案例无关,而在头文件中定义此函数是一种完全有效的方法。
        【解决方案5】:

        您还可以创建一个 Util 结构,其中每个函数都声明为静态。然后你可以使用Util::<function name>访问每个函数

        文件 UTIL.h

        #ifndef UTIL_H_
        #define UTIL_H_
        
        struct Util{
            static int aplusb(int a, int b) {
                return a + b;
            }
        };
        
        #endif /* UTIL_H_ */
        

        文件类A.cpp

        #include "ClassA.h"
        #include "UTIL.h"
        
        ClassA::ClassA() {
            sum = Util::aplusb(3,5);
        }
        
        ClassA::~ClassA() {
        }
        

        文件类B.cpp

        #include "ClassB.h"
        #include "UTIL.h"
        
        ClassB::ClassB() {
            sum = Util::aplusb(5,6);
        }
        
        ClassB::~ClassB() {
        }
        

        【讨论】:

          猜你喜欢
          • 2018-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-02-29
          • 1970-01-01
          • 1970-01-01
          • 2021-12-06
          相关资源
          最近更新 更多