实现一个尚未编译的接口,.cpp包括?

时间:2012-10-24 21:17:14

标签: c++ visual-studio-2010 visual-studio

我正在使用VS2010,我正在设计一个MVC应用程序。

说我在解决方案中有“Project 1”和“Project 2”。需要按顺序编译,P1编译为DLL,P2编译为动态使用DLL的Exe文件。 P2声明了一个视图接口。两个项目都有一个实现接口的视图类(一个具有纯虚方法的类)。

现在的问题是,我不能在P1中包含接口的头文件,因为链接器会说他无法解析这个外部符号。这当然是正确的,因为它稍后在P2中编译。

所以我做的是,我将P2的include文件夹添加到P1,并在P1中包含了interface.cpp而不是头文件。

它有效,但我不认为这是我应该做的。或者不是吗?界面显然是编译两次,每个项目一次。

我不想将界面移动到P1,这将解决问题。假设,我不希望这样。

感谢您提供意见。

编辑:代码段:

Project1:

View1.hpp // nothing special

View1.cpp:

#include ViewInterface.cpp
View1::View1(int x) : ViewInterface(int x)

Project2:

ViewInterface.hpp:

#ifdef EXP
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif

class ViewInterface : SomeOtherClass, AnotherClass
{
  virtual void DECLDIR show(void) const = 0;
  virtual void DECLDIR hide(void) const = 0;
}

ViewInterface.cpp:

ViewInterface::ViewInterface(int x) : SomeOtherClass(int x), AnotherClass(int x)

View2.hpp // nothing special

View2.cpp:
#define EXP
#include ViewInterface.h

View2::View2(int x) : ViewInterface(int x)

2 个答案:

答案 0 :(得分:1)

为了使可执行文件能够使用DLL中的类,您需要确保它们已正确导出。编译DLL时,使用__declspec(dllexport)标记该类,并在编译可执行文件时,使用__declspec(dllimport)标记该类。通常,这是通过如下宏来完成的:

// In your DLL's header file
#ifdef COMPILING_MY_DLL
#define MY_EXPORT __declspec(dllexport)
#else
#define MY_EXPORT __declspec(dllimport)
#endif

class MY_EXPORT MyClass
{
    ...
};

然后,在您的DLL项目中,您定义宏COMPILING_MY_DLL

答案 1 :(得分:0)

  

我不想将界面移动到P1,会解决什么问题   问题。假设,我不希望这样。

然后将其移至第三个实体。

你必须决定什么对你更重要。如果你想要一个干净的解决方案,那么要么将接口定义移动到DLL(P1),要么移动到DLL和EXE都可以使用的东西 - 我们称之为“P0”。 P0甚至不必是被编译的东西 - 一个简单的头文件在它自己的目录中,所有内联定义的内容都可以。我首选的选择是让P0成为一个DLL。

这是唯一清洁解决方案。以下“解决方案”实际上只是我为了完整而描述的黑客。


如果你真的想要“脏”的解决方案,那么就这样做吧,唯一不同的是你将定义接口的头文件放在application-source-folder中。

如果你想要它非常脏,那么在构建你建议的DLL时包含.cpp文件。它也会起作用......它真的很糟糕。

当然你必须要注意一些事情。例如。 “接口”不应该有任何静态数据成员,并且“接口”中的任何功能都不应具有本地静态功能。因为如果它们这样做,那么这些静态变量将被实例化两次 - 一次在DLL中,一次在EXE中。此外,由于所有代码都将编译到两个项目中,因此如果要更改任何内容,则必须重新编译这两个项目。 (代码在DLL和EXE中重复,只要它们是从相同的代码编译就不是问题。)

如果您选择“P0 =只是头文件”解决方案,那么这些限制当然也适用。


最后真的是非常糟糕的超级解决方案:在EXE中实现接口,从EXE实现dllexport并在DLL中进行dllimport(是的,可以做到!)。缺点是您必须进行特殊的EXE构建,只构建EXE的导入库(可以在没有DLL的导入库的情况下完成)。使用EXE的导入库,您可以构建DLL,然后使用DLL的导入库,您可以构建EXE本身。 这样“接口”甚至可以拥有静态数据成员,如果只更改代码(即头文件没有变化),那么你只需要重新编译EXE。