*******编辑*******
一位读者建议我的问题与找到的问题here重复。对这个问题的主要回答提供了两个解决方案:
由于我已尝试过此解决方案,因此这不是一个重复的问题。
问题,正如下面的Ben Voigt所解决的(谢谢),与Visual Studio有关。更改"项目类型"来自" C / C ++编译器"到" C / C ++标题"因为MyClass.cpp文件解决了这个问题。
****结束编辑****
我是c ++的初学者,我遇到了尝试在Visual Studio 2015中编译以下程序的问题。使用我的Mac上的clang编译器编译好的程序。该程序还使用VS2015的Developer Command Prompt中的cl.exe进行了编译。我想这意味着在我的Visual Studio项目中配置错误,但我还没有找到解决方案。
以下是代码:
/** @file MyInterface.h */
#ifndef MY_INTERFACE_
#define MY_INTERFACE_
template<class ItemType>
class MyInterface
{
public:
virtual void sayHello() const = 0;
};
#endif
/** @file MyClass.h */
#ifndef MY_CLASS_
#define MY_CLASS_
#include "MyInterface.h"
template<class ItemType>
class MyClass : public MyInterface<ItemType>
{
private:
ItemType myItem;
public:
MyClass();
void setItem(const ItemType& newItem);
void sayHello() const;
};
#include "MyClass.cpp"
#endif
/** Implementation file for MyClass.
@file MyClass.cpp */
#include "MyClass.h"
#include <iostream>
template<class ItemType>
MyClass<ItemType>::MyClass()
{
}
template<class ItemType>
void MyClass<ItemType>::setItem(const ItemType& newItem)
{
myItem = newItem;
}
template<class ItemType>
void MyClass<ItemType>::sayHello() const
{
std::cout << "Hello! My Item is: " << myItem << std::endl;
}
/** @file test.cpp */
#include "MyClass.h"
#include <string>
int main()
{
MyClass<std::string> classOne;
classOne.setItem("foo");
classOne.sayHello();
MyClass<int> classTwo;
classTwo.setItem(7);
classTwo.sayHello();
}
当我将这些文件合并到一个目录中并运行命令时:
cl test.cpp
来自VS2015的开发人员命令提示符,它正确编译。我得到一个test.exe可执行文件,它返回:
test.exe
Hello! My item is: foo
Hello! My item is: 7
到目前为止,非常好。
当我尝试在Visual Studio 2015中完成此项目时,问题就开始了。我开始了一个#34;空项目&#34;对于Visual c + +并添加了这些完全相同的文件。但是,当我构建项目时,我收到错误消息:
Error C2995 'MyClass<ItemType>::MyClass(void)': function template has already been defined
Error C2995 'void MyClass<ItemType>::setItem(const ItemType &)': function template has already been defined
Error C2995 'void MyClass<ItemType>::sayHello(void) const': function template has already been defined
错误消息让我相信我有循环依赖。罪魁祸首似乎是MyClass.h文件中的#include "MyClass.cpp"
,但这对于模板编译是必要的。如果没有这种包含,编译器就无法看到模板的实例化,也不知道与泛型类型ItemType
对应的实际数据类型(或者我的教科书说的那样)。
为了满足Visual Studio构建过程,我从MyClass.h文件中删除了#include "MyClass.cpp
,但后来我收到了这些错误:
Error LNK2019 unresolved external symbol "public: __thiscall MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(void)" (??0?$MyClass@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QAE@XZ) referenced in function _main
Error LNK2019 unresolved external symbol "public: __thiscall MyClass<int>::MyClass<int>(void)" (??0?$MyClass@H@@QAE@XZ) referenced in function _main
Error LNK2019 unresolved external symbol "public: void __thiscall MyClass<int>::setItem(int const &)" (?setItem@?$MyClass@H@@QAEXABH@Z) referenced in function _main
有六个这样的错误(只显示了三个),都是未解析的外部符号。
此时我不知道还有什么可以尝试。如果我将实现文件包含在头文件中,编译器会因为存在循环依赖关系而对我大吼大叫,如果我不在头文件中包含实现文件,那么我有未解析的外部符号。
非常感谢有关此问题的任何帮助:)
答案 0 :(得分:2)
因为你#include
MyClass.cpp,它本身不是一个编译单元,它是一个头文件。确保Visual Studio被告知不要单独构建它,默认情况下它假定.h
文件是标题,.cpp
是每个单独编译的单元。
访问项目属性并将“项目类型”从“C / C ++编译器”更改为“C / C ++标题”。
这有效地将构建命令更改为工作版本
cl test.cpp
来自通过添加所有文件生成的默认(有效)命令
cl test.cpp MyClass.cpp
如果您在命令行输入错误,则会导致完全相同的错误。
还有其他方法可以完成从构建命令中删除它,例如在解决方案资源管理器的右键菜单中找到的“从项目中排除文件”,但这使得编辑/导航不太方便。将其正确标记为头文件将为您提供调试期间Intellisense自动完成,Goto定义和源视图的最佳体验。