- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我试图增加我对基本库链接、依赖关系等的理解。我创建了一个包含三个项目的 Visual Studio 解决方案
静态 lib
使用 /MTd
有一个类( Foo
),一个方法 int GetNum() { return 5; }
共享 dll
使用 /MDd
有一个类( Bar
),一个方法 int GetNum() { Foo f; return f.GetNum(); }
Win32 控制台应用程序。那叫Bar b; std::cout << b.GetNum() << std::endl
当我尝试构建它时,它提示找不到我的 dll 的关联库。做了一点研究,发现我需要添加 __declspec(dllexport)
到我的GetNum()
方法,我会得到一个 .lib
.很酷。
下一个障碍是控制台应用程序说它找不到 Foo
的静态库.我将它添加到我的引用资料中,并且一切都正常运行。
我的问题是 - 为什么我的 exe 需要知道关于 Foo
的任何信息? ?我想有效地将我所有的依赖项“烘焙”到 dll 中,这样我就可以共享它,链接到它,然后就可以开始了。
这不是语言的工作方式还是我缺少的设置/模式?我的最终目标是能够构建一个 dll 来封装第三方 .lib 的使用,而不是让客户端应用程序需要担心添加对所有这些的引用。
更新
这里是大部分代码。
// ---------------------- Lib (e.g. Foo)
#pragma once
class MathLib
{
public:
MathLib(void);
~MathLib(void);
int GetNum() { return 83; }
};
// ---------------------- DLL (e.g. Bar)
#pragma once
#ifdef CONSOLETEST_EXPORT
#define CONSOLETEST_API __declspec(dllexport)
#else
#define CONSOLETEST_API __declspec(dllimport)
#endif
#include "MathLib.h"
class MathDll
{
public:
__declspec(dllexport) MathDll(void);
__declspec(dllexport) ~MathDll(void);
__declspec(dllexport) int GetNumFromDyn()
{
MathLib m;
return m.GetNum();
}
};
// ---------------------- exe
int _tmain(int argc, _TCHAR* argv[])
{
MathDll m;
std::cout << "num is " << m.GetNumFromDyn() << std::endl;
return 0;
}
最佳答案
对于 C/C++,在 headers(例如 h
、hpp
、hxx
、h++
等)和翻译单元(通常称为 sources,例如 c
、cpp
、cxx
、c++
等)。当您设计一个库时,您应该不断思考什么属于它的接口(interface)(即应该被消费者看到)以及什么属于它的实现(即不应该被消费者看到)。
记住经验法则 - 任何 header 中出现的所有符号都会被消费者看到(如果包含的话),因此消费者需要稍后在链接阶段解决!
这基本上就是您在玩具示例中发生的情况。因此,让我们使用一个您应该牢记的简单规则来解决它:尽可能多地放入翻译单元,即保持标题最少。现在让我们使用您的示例来说明它是如何工作的:
MathLib.hpp
:
#pragma once
class MathLib {
public:
MathLib();
~MathLib();
int GetNum();
};
MathLib.cpp
:
#include "MathLib.hpp"
MathLib::MathLib() {}
MathLib::~MathLib() {}
int MathLib::GetNum() { return 83; }
现在构建 MathLib.cpp
作为静态库。
MathDll.hpp
:
#pragma once
#ifdef CONSOLETEST_EXPORT
# define CONSOLETEST_API __declspec(dllexport)
#else
# define CONSOLETEST_API __declspec(dllimport)
#endif
class CONSOLETEST_API MathDll {
public:
MathDll();
~MathDll();
int GetNumFromDyn();
};
MathDll.cpp
:
#include "MathDll.hpp"
#include "MathLib.hpp"
MathDll::MathDll() {}
MathDll::~MathDll() {}
int MathDll::GetNumFromDyn() {
MathLib m;
return m.GetNum();
}
现在将 MathDll.cpp
构建为动态链接库 (DLL),不要忘记在其构建过程中添加定义 CONSOLETEST_EXPORT
,以便 CONSOLETEST_API
是 __declspec(dllexport)
,因此,一个带有导出符号的导入库(即 MathDll
类及其方法) 是为 DLL 生成的。在 MSVC 上,您可以通过将 /DCONSOLETEST_API
添加到编译器调用来实现此目的。最后,在构建这个 DLL 时,一定要将它与之前构建的静态库 MathLib.lib
链接起来。
注意:最好像我上面对 class CONSOLETEST_API MathDll
那样导出整个类,而不是单独导出所有方法。
main.cpp
:
#include "MathDll.hpp"
#include <iostream>
int _tmain(int argc, _TCHAR* argv[]) {
MathDll m;
std::cout << "num is " << m.GetNumFromDyn() << std::endl;
return 0;
}
现在构建 main.cpp
作为控制台应用程序 并且只将它与之前构建的 DLL 导入库链接,MathDll.lib
。
请注意问题是如何解决的,因为我已经摆脱了 main.cpp
对 MathLib
的传递依赖(通过 MathDll.hpp
) >,因为现在 #include "MathLib.hpp"
包含在翻译单元 MathDll.cpp
中完成(因为根据上述规则实际上只需要在那里),并且因此内置于二进制工件(在本例中为 DLL)中,而不存在于其界面中。
了解所有这些对于使用 C/C++ 进行适当的 native 软件开发非常重要,因此您最好事先提出这个问题。我经常遇到不知道/不理解这一点的人,这对他们(业余爱好者)和我们来说是一场噩梦,当我们不得不处理他们编写的糟糕软件时......
关于c++ - 将静态库封装在动态链接库 (DLL) 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20925478/
我需要使用封装打印3个变量,并且无法修改主类。 主类声明变量[汽缸、制造商、所有者],并希望使用如下参数创建和打印一个对象: System.out.println (new Vehicle (cyli
我正在研究“Beginning Ruby”这本书,在我进行封装之前一切都进行得很顺利。我明白这段代码在做什么,我只是不知道为什么要用这些方法设置它。 对于那些感兴趣的人 this is the lin
所以我一直在研究面向对象的完整开发 JavaScript 实践,并对以下示例感到好奇。 据我了解,(这对我来说很有意义)以下“ secret ”字段是“私有(private)”的: var MyObj
在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装、隐藏起来的方法。 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代
封装 被定义为 把一个或多个项目封闭在一个物理的或者逻辑的包中 。在面向对象程序设计方法论中,封装是为了防止对实现细节的访问。 抽象和封装是面向对象程序设计的相关特性。抽象允许相关信息可
今天我读了一本书,作者写道,在一个设计良好的类中,访问属性的唯一方法是通过其中一个类方法。这是一个被广泛接受的想法吗?为什么封装属性如此重要?不做会有什么后果?我早些时候在某处读到这可以提高安全性或类
今天我接受了软件工程职位的面试。我已经从 stackoverflow 中阅读了很多关于面试的内容。他们向我询问了与 OOP 相关的正常情况。但他们也问我这些: 没有继承就可以封装吗? 没有继承就可以抽
我正在制作一个简单的网站,并编写了gradle构建脚本,该脚本将执行诸如lint并最小化css / html / js之类的事情。 在这一阶段,我刚刚完成了正在运行的CSS,但是只是初始的非结构化格式
下面的幻灯片是指 C++ 语言,它说 "encapsulation is about ensuring the user uses our ADT in a safe way" 但是,如果他可以访问我
尝试设置一个 Person 类 我在尝试将信息封装在类中以使其不会被意外更改时遇到了问题。除了当我尝试使用 setter/getters 进行封装时,该类工作得非常好。我认为问题是这些方法最终会互相循
面向对象的概念:封装、数据抽象和数据隐藏是3个不同的概念,但彼此之间非常相关。所以我很难通过阅读互联网上的信息来完全理解这些概念。一个地方可用的信息与互联网上另一个地方的信息相矛盾。有人可以指导我阅读
我被封装困住了。在我看来,好像我已经按照规则做了一切,但仍然不起作用。虽然我知道我错过了一些东西。我正在使用 Eclipse。 我想要通过创建一副标准 52 张卡片来进行一些练习,并尝试我学到的新东西
在java中,要获取映射中的所有键,我们可以使用方法keySet。但我想知道为什么方法名称不只是 keys ?名称 Set 是否会泄露有关实现的详细信息? 据我了解,Java 是静态类型语言,名称中包
我正在尝试找出如何防止应用程序中的页面变量被全局定义。我想出了一些方法,但我想知道是否有人们使用的通用标准方法。 我使用这种方法得到了我的插件设计模式:http://www.virgentech.co
我有一个 tcp 连接,我想在服务器类的 HandleConnectionAsync 方法中保持打开状态。它将从客户端接收持续更新。 private async void HandleConnecti
这是我类(class)的一个小样本: #include #include using std::string; using std::vector; struct Book { string
我想要类似下面的代码: class Foo{ public: void update() { for( auto dataModifier : _dataModifierLis
这已经困扰我一段时间了,所以我问了一个同事他是否能理解它,现在我来了;) 为什么可以在依赖属性的 PropertyChangedCallback 中访问持有类的私有(private)成员? 让我通过这
我知道封装意味着一个对象不应该直接访问不同对象的成员……但我猜它与公共(public)领域有关?我假设公共(public)方法不会破坏封装..?我只是在这里不清楚,很高兴得到任何解释。 最佳答案
我就废话不多说了,大家还是直接看代码吧~ ? 1
我是一名优秀的程序员,十分优秀!