【问题标题】:trying to simultaneously compile three template .cpp files causes "error: redefinition of method"尝试同时编译三个模板 .cpp 文件会导致“错误:重新定义方法”
【发布时间】:2020-02-21 09:35:51
【问题描述】:

我有一个大学项目,我设法使用自己的 makefile/终端命令开始工作。但是我在大学的自动标记上得了零分。我认为这是因为他们使用了一个 makefile,它试图在编译器的一行中执行所有三个 cpp 文件(如果这甚至可能的话),这很难说,因为标记没有给出任何反馈。当我尝试编译所有三个 .cpp 文件(g++ main.cpp A.cpp B.cpp)时,我收到以下错误消息:

  • B.cpp:4:3:错误:重新定义“T B::getVal()” T B::getVal(){
  • A.cpp:4:6:错误:重新定义“void A::print(B)” void A::print(B bInstance){

在我的 MRE 中,以下内容需要保持不变:

  • A 和 B 必须有 .h 和 .cpp 文件
  • main.cpp 只能包含“A.h”
  • A 必须要求 B 才能工作

这是我的 MRE: - 它创建 B 的实例,然后使用 A 的实例打印具有实例 B 值的消息。

main.cpp

#include "A.h"

int main(){
  B<char> b1;
  b1.val='B';
  A<char> a1;
  a1.print(b1);
}

啊.h

#ifndef AAAA
#define AAAA

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

using namespace std;

template <class T>
class A{
public:
  void print(B<T> bInstance);
};

#include "A.cpp"

#endif

A.cpp

#include "A.h"

template <class T>
void A<T>::print(B<T> bInstance){
  cout<<"I am A, and I am using "<<bInstance.getVal()<<endl;
}

B.h

#ifndef BBBB
#define BBBB

template <class T>
class B{
public:
  T val;
  T getVal();
};

#include "B.cpp"

#endif

B.cpp

#include "B.h"

template <class T>
T B<T>::getVal(){
  return val;
}

工作编译和运行命令

g++ main.cpp

./a.out

它应该使用的命令(如果可能的话)

g++ main.cpp A.cpp B.cpp

./a.out

【问题讨论】:

  • 我还是新手,我意识到我用太多词来描述我的问题。我试图减少它,但如果这仍然太多,请告诉我。
  • 不包含 cpp 文件。

标签: c++ linux templates header linker


【解决方案1】:

你不应该在标题中使用#include ".cpp"。函数模板的实现必须在标头中,而不是在cpp 中。在您的示例中,根本不需要 A.cppB.cpp。如果任务仍然需要它们,请将它们设为空,#include 指令除外。

编辑:如果您的自动标记不喜欢它,您也可以尝试内联您的实现,例如

template <class T>
class B{
public:
  T val;
  T getVal(){
     return val;
  }
};

【讨论】:

  • 自动标记会检测您何时将实现放在头文件而不是 .cpp 文件中,所以我仍然会得到零,但谢谢。
  • 您确定即使对于 template 实现也是如此?如果是这样,我会说这是标记中的错误。
  • 是的,我确定。我认为有办法做到这一点,但很难知道,因为我们不知道 makefile 是什么样子,也不知道它们运行什么测试代码,甚至不知道编译器给出了什么错误。
【解决方案2】:

您现在的文件问题在于,当您尝试编译 B.cpp 时,会出现以下问题:

#include "B.h"

template <class T>
T B<T>::getVal(){
  return val;
}

还有这个:

#ifndef BBBB
#define BBBB

template <class T>
class B{
public:
  T val;
  T getVal();
};

#include "B.cpp"

#endif

组合成这样:

#ifndef BBBB
#define BBBB

template <class T>
class B{
public:
  T val;
  T getVal();
};

#ifndef BBBB     // <- BBBB has been defined at this point, so everything between  this and the #endif is skipped
#endif

template <class T>
T B<T>::getVal(){
  return val;
}

#endif

template <class T>
T B<T>::getVal(){
  return val;
}

在这一点上,我希望您收到错误的原因很明显:B.cpp:4:3: error: redefinition of ‘T B::getVal()’ T B::getVal(){

正确的解决方法是将整个模板实现放在标题中,并删除.cpp 文件。但是,如果由于自动标记混乱而无法选择此选项,请尝试将 include-guards 添加到 .cpp 文件中。但是请注意,这是一种不好的做法(.cpp 文件不应该是 #include'ed,因此不应该需要包含保护),所以如果有人看到你的代码,那么准备好迎接很多问题和扬起眉毛。

但是!第一步可能应该是尝试与给你任务的人交谈,因为这里有问题;使用自动标记或您对其工作原理的理解。模板类应该.cpp 文件(或者它应该是空的)。

【讨论】:

  • 我同意#include .cpp 文件是不好的做法。我与主题管理员交谈,在这种特殊情况下,我们应该#include .cpp 文件。我会和他们谈谈,看看他们怎么说。非常感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 2015-07-02
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多