【问题标题】:Include in main and class body returns multiple definition error包含在主体和类主体中返回多个定义错误
【发布时间】:2017-06-13 04:32:06
【问题描述】:

我正在尝试编译一个包含类头的主函数。主函数以及类 cxx 文件使用一个名为“SayHello”的辅助函数。但是,如果我在主文件和类 cxx 文件中包含帮助文件“Hello.h”,则会出现多重定义错误。我在下面放了一些最小的例子。你能帮帮我吗?

干杯, 安德烈亚斯

Main.cxx:

#include "Class.h"
#include "Hello.h"

int main(int argc, char **argv){
    SayHello();
    return 0;
}

类.h

#ifndef CLASS_H
#define CLASS_H

class Class {
public:
    Class();
    ~Class();
};

#endif

类.cxx

#include "Class.h"
// #include "Hello.h" //with this it breaks!

Class::Class(){
    // SayHello(); //with this it breaks!
}

你好.h

#ifndef HELLO_C
#define HELLO_C

#include <iostream>

void SayHello(){
  std::cout<<"hello!"<<std::endl;
}

#endif

我的生成文件:

# Compiler
CXX           = $(shell root-config --cxx)

# Compiler flags
ROOTCFLAGS   := $(shell root-config --cflags)
ROOTLIBS     := $(shell root-config --libs)
CFLAGS        = -Wall ${ROOTCFLAGS} ${INCLUDE_PATH}
LFLAGS        = -O3 ${ROOTLIBS} -lHistPainter

# Targets
EXE = Main
OBJS = Main.o Class.o

# Processing
# -------------------------------------
all: ${OBJS} ${EXE}
    @echo "Done"

${EXE}: ${OBJS}
    @echo "Making executable $(notdir $@)"
    ${CXX} ${CFLAGS} ${OBJS} ${LFLAGS} -o $@

${EXE}.o: ./${EXE}.cxx
    @echo "Compiling $(notdir $<)"
    ${CXX} $(CFLAGS) -c $< -o $@ 

%.o: ./%.cxx ./%.h
    @echo "Compiling $(notdir $<)"
    ${CXX} $(CFLAGS) -c $< -o $@ 

clean:
    @echo "Cleaning"
    @rm -f ./Main
    @rm -f ./Main_cxx.so
    @rm -f ./Main_cxx.d
    @rm -f ./*.o
    @rm -f ./*ACLiC_dict_rdict.pcm

【问题讨论】:

  • 创建hello.hhello.cpp,并用与你的类相同的方式分离“sayHello”的声明和定义
  • 或者,因为这是 C++,所以将 SayHello 函数定义为 inline
  • 谢谢大家!我是新来的,所以我现在才看到你的回复,可能没有对赞成票和其他东西做出相应的反应。我要学那个!干杯!
  • 请注意,您在 Hello.h 中的包含保护可能应该命名为 HELLO_H 而不是 HELLO_C

标签: c++ class main


【解决方案1】:

您将SayHello 函数的定义放在头文件中。这是错误的。

由于您将此头文件包含在两个不同的文件中,因此该定义被编译了两次,在两个不同的文件中,您的链接器最终会在最后看到同一个函数的两个定义。

这就是为什么你的头文件 Hello.h 应该只包含函数的原型:

#ifndef HELLO_C
#define HELLO_C

void SayHello();

#endif

虽然定义应该在单独的 Hello.cxx 文件中:

#include <iostream>
#include "Hello.h"

void SayHello(){
  std::cout<<"hello!"<<std::endl;
}

当然,不要忘记将这个新文件添加到您的 Makefile 中:

OBJS = Main.o Class.o Hello.o

更新:

正如Rene 所说,您还可以通过在标题中添加inline 关键字来简单地将您的函数声明为内联。它会让你的编译器在每次调用这个函数时复制整个函数内容,而不是做一个函数调用。

这通常用于非常短的函数,通常是 getter 和 setter 函数。由于您的函数只是一个“Hello”打印,因此将其设为内联函数可能不是一个坏习惯。

但要小心:代码中的内联函数过多会减慢编译速度,并增加包含依赖。例如,如果您内联SayHello 函数,则任何包含"Hello.h" 的文件也应包含&lt;iostream&gt;

【讨论】:

  • 其实我找到了一个额外的方法,它可以避免有两个文件,它只是用内联静态 void SayHello() 替换 void SayHello()。这是不好的做法吗?
  • 我怀疑在将函数测量为性能瓶颈之前内联函数是一种好习惯。
猜你喜欢
  • 2022-09-28
  • 2021-05-21
  • 2014-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多