我的手上有一个谜。我正在尝试学习来自C#背景的托管C ++,并遇到了麻烦。如果我有一个包含两个类的项目,一个基类 Soup 和一个派生类 TomatoSoup ,我将其编译为静态库(.lib),我得到了未解析的标记汤中的虚拟方法。这是代码:
Soup.h
namespace Abstracts
{
public ref class Soup abstract
{
public:
virtual void heat(int Degrees);
};
}
TomatoSoup.h
#include "Soup.h"
namespace Abstracts
{
public ref class TomatoSoup : Abstracts::Soup
{
public:
virtual void heat(int Degrees) override;
};
}
TomatoSoup.cpp
#include "TomatoSoup.h"
void Abstracts::TomatoSoup::heat(int Degrees)
{
System::Console::WriteLine("Soup's on.");
}
Main.cpp的
#include "TomatoSoup.h"
using namespace System;
int main(array<System::String ^> ^args)
{
Abstracts::TomatoSoup^ ts = gcnew Abstracts::TomatoSoup();
return 0;
}
我在 Main.proj 上收到此链接时错误:
1>Main.obj : error LNK2020: unresolved token (06000001) Abstracts.Soup::heat
我尝试过设置
virtual void heat(int Degrees)=0;
我尝试在基类中实现热量
virtual void heat(int Degrees){}
并得到一个未引用的正式 参数警告视为 错误。
这个问题让我发疯,我希望将来能阻止其他开发商疯狂。
UPDATE:当在头文件中实现TomatoSoup :: heat时,这与Greg Hewgill的参数名称注释方法一起使用,但是当我将实现移动到TomatoSoup.cpp时,错误又回来了。我修改了这个问题以反映这一点。
答案 0 :(得分:3)
您收到的错误(LNK2020)表示链接器无法在任何地方找到Abstracts.Soup::heat
函数的定义。当您将函数声明为virtual void heat(int Degrees);
时,链接器将期望找到在某处定义的函数体。
如果您打算不提供函数体,并且要求子类最终覆盖该函数,则应按照解决方案1中的说明进行操作:
virtual void heat(int Degrees) = 0;
这告诉编译器你不打算实现这个功能。当你这样做会发生什么?
另外,参考您的第二个解决方案:
virtual void heat(int Degrees) {}
编译器告诉您不要在函数中引用Degrees参数。在C ++中避免此警告的一种方法是不为参数指定名称:
virtual void heat(int /*Degrees*/) {}
但是,提供一个空实现与纯虚拟(= 0
)声明略有不同。
答案 1 :(得分:2)
我认为可能发生了这个错误,因为我试图将Abstracts.proj构建为静态库。当我将其更改为.DLL时,一切正常。
我已经看到过提到静态库不支持托管代码,但没有官方提供。有没有人有一个很好的参考说明这个?
答案 2 :(得分:0)
我没有太多的CLI经验,但我认为你应该使用public继承:
公共参考类TomatoSoup:公共摘要::汤