创建包含多个类的库的推荐方法是什么?< / h1 >
What is the recommended method for creating a library with multiple classes?
我对c++比较陌生(之前有Python的经验和Java的涉水),我正在编写一个小程序作为一个熟悉项目。作为程序的一部分,我正在编写一个类来解码一些数据,并最终将编写一个类似的类来执行编码。我相信我会经常重用这些代码,并且认为创建一个库作为项目的一部分会很有趣。我的问题是,创建库的最佳实践是什么?
编辑:(修订)
问了这个问题之后,我意识到我不知道我不知道什么。我做了更多的研究,这应该有助于使我的问题更具体:- 我正在Qt Creator中开发。所以有关Qt的细节将是有帮助的,但不是必要的。
- 我在Qt (MyCodec)中创建了一个新的静态库项目,目前,有一个类定义为MyDecoder。
- 作为一个库,我的假设是,添加MyEncoder,我只是创建另一个类/头文件。
- 接下来会发生什么是我不确定的。我只需要建立图书馆吗?我的理解是,它将创建(在Windows中)一个。lib和一个。h文件。在这一步之前,我应该做些什么吗?是否有选项会影响我与它的交互方式?
- 我只是包括头文件在我的程序访问两个类,我写的?
- 我发现了很多关于在Qt中添加.lib文件到项目的答案,所以我不需要这些信息。
原问题:(用于上下文)
我最初的想法是,创建包含MyEncoder和MyDecoder类的MyLib将是最方便的。
如果我要这样做,我只是在头文件中声明两个类吗?
我想创建一个DLL从这个库的可移植性和经验。我相信有很多关于创建和使用dll的信息(这不是这个问题的主题),但如果有一个特别好的教程(Qt),请把它传给我。
我的假设是,最好为MyEncoder和MyDecoder使用单独的名称空间,以实现与MyLib的一个名称空间?
我可以看到这种方法的一个折衷是应用程序的大小,因为包含MyLib.h将包括编码器和解码器的代码(如果编码器和解码器是单独的应用程序)。这是假设我没有使用DLL。
我想我的意思是:
- 有哪些可用的(和推荐的)方法?
- 两者的权衡是什么?
- 我在哪里可以找到关于这个特定主题的文档(教程/示例)?我的搜索努力并没有产生多少结果。
如果它有助于更具体,我正在Qt Creator中使用Qt 4.7.4进行开发。
c++中关于库的一个"最佳实践"通常是"为所使用的东西付费"。
这如何适用于你的问题是,你会有MyEncoder和MyDecoder在单独的头文件。所以如果用户想要使用MyEncoder他会包括MyEncoder.h,如果他想要使用MyDecoder他会包括MyDecoder.h,如果他想要使用两者他会包括两个头。
链接器通常只包含您在可执行文件中使用的部分代码,因此就代码大小而言没有损失,但是在编译时间上有损失,特别是当您开始在类中使用高级模板技术时。在大型项目中,编译时间可能会相当长,因此能够只包含您将要使用的内容是很重要的。
当然,有时用一个头文件包含所有内容也很方便。所以你可以这样写:- MyEncoder.h
- MyDecoder.h
- MyCodec.h
然后MyCodec.h可以同时包含MyEncoder.h和MyDecoder.h
假设MyEncoder和MyDecoder对相同类型的数据进行操作,那么可能没有很好的理由将它们放在不同的命名空间中。
你可能想要一个类似于MyCodec的名称空间,并在该名称空间中声明MyEncoder和MyDecoder。
为您的修订而更新:
作为一个库,我的假设是,添加MyEncoder,我只是创建另一个类/头文件
这个假设是正确的。
接下来发生的是我不确定的地方。我只是建立图书馆吗?我的理解是,它将创建(在Windows中)一个.lib和一个。h文件。在这一步之前,我应该做些什么吗?是有哪些选项会影响我与它的交互方式?
我有一段时间没有使用Qt creator,所以我不能就它或如何访问相关选项与权威交谈。但一般来说,你的库至少要有两个版本;一个调试版本和一个发布版本。如果你的库使用Qt库,那么当一个应用程序链接到你的库的调试版本时,他们将需要在他们的路径中有Qt共享库的调试版本,如果他们链接到你的发布版本,他们将需要有Qt库的发布版本。
还可以选择是静态链接到c++标准运行时库,还是动态链接到dll。
但本质上是的,你只是构建了库,然后使用它的应用程序将库链接到可执行文件。
我只是在我的程序中包含头文件来访问这两个吗我写的类呢?
包含头文件,并链接到.lib文件。这就是你所需要做的。
这适用于Qt Creator 2.4.1。
首先,要使用和调试库,您需要有一个分层的顶级项目,其中包含两个子项目:一个用于库,另一个用于使用库的应用程序。这样,Creator将在运行应用程序之前重新构建更改的所有内容——因此,如果您更改了库源文件,库将自动重新构建以及应用程序将被重新链接。
我将一步一步地展示如何创建所需的三个项目(库、应用程序和顶部项目),最终得到一个可构建、可调试的最小应用程序和库。您可以按照相同的步骤轻松地添加更多的子库。
创建项目
-
为你的项目创建一个文件夹
-
高级项目
File->New File or Project, Other Project, Subdirs Project, Choose
将项目命名为- 点击"完成"添加子项目">
top
,并将其放入步骤1中创建的文件夹中。 -
Library Project -新项目窗口从上一步点击进入。
Other Project, C++ Library, Choose
- 类型:改为静态链接库
- 将项目命名为
library
,并将其放在前面创建的top
文件夹中的一步。这个文件夹应该是默认选中的。 - 点击通过,选择QtCore模块将被库项目使用,其余一切保持默认值
-
应用程序项目-右键单击项目窗格中的
top
项目(不在top.pro上)Qt Widget Project, Qt Gui Application, Choose
- 将项目命名为
app
并将其放入步骤2中创建的top
文件夹中。这个文件夹应该是默认选中的。
点击完成,保持默认设置。
你现在应该有一个可构建的top
项目,app
和library
作为子项目。按C-B (Ctrl-B或Command-B,取决于您的平台)来构建它。构建过程应该没有错误。
设置依赖
链接到图书馆
app
子项目还没有使用我们的库。将app
链接到我们的库:
-
右键单击项目窗格中的
app
(而不是app.pro中的),选择Add Library...
-
选择
Internal Library
, Continue library
是唯一的选择,并且已经被选中。
app
项目现在与library
静态链接。更改app
项目中的任何文件(空格更改即可)以强制构建,然后按C-B进行构建。构建过程应该执行OK。
添加对库的顶层依赖
如果库被更改,app
子项目将被重新构建,但是没有什么可以保证make系统在开始构建应用程序之前首先构建库子项目。这些信息属于顶层top.pro
项目文件。
打开top.pro
,添加一行CONFIG += ordered
。该文件看起来应该像这样:
TEMPLATE = subdirs
SUBDIRS +=
library
app
CONFIG += ordered
确保SUBDIRS顺序正确:库优先于应用程序。如果顺序错误,您可以将条目洗牌到正确的顺序。反斜杠是一个行延续字符。
后不能有空格
保存文件(C-S),右键单击top
项目,选择Rebuild project "top"。构建完成时应该没有错误。
选择Build
在Qt Creator的左下角面板中,有一个带有构建按钮(锤子),运行按钮(三角形),调试按钮(带有错误的三角形),构建选择器(上面有top
项目名称的笔记本电脑,下面省略了构建配置)的面板。单击构建选择器,并确保选择以Debug
结尾的构建。此构建被配置为生成在调试器下运行它所需的调试符号。我们以后会需要的。
实现库
我们现在将一些代码添加到由Qt Creator为我们创建的Library类中。打开"library.h
"answers"library.cpp
"文件。添加的代码只是Library类中的一个静态方法。此方法将在应用程序中使用,以显示两个部分实际上被链接。两个文件的内容如下:
//library.h
#ifndef LIBRARY_H
#define LIBRARY_H
#include <QString>
class Library {
public:
Library();
static QString string();
};
#endif // LIBRARY_H
//library.cpp
#include "library.h"
Library::Library()
{}
QString Library::string()
{
return "I come from the library";
}
点击C-B,代码将重建,没有错误。
实现应用程序
现在让我们使用app
中的库API。打开mainwindow.cpp
和mainwindow.h
文件,修改如下:
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QScopedPointer>
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QScopedPointer<Ui::MainWindow> const ui;
};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include <QVBoxLayout>
#include <QLabel>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "library.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVBoxLayout * layout = new QVBoxLayout();
QLabel * label = new QLabel(Library::string(), centralWidget());
layout->addWidget(label);
centralWidget()->setLayout(layout);
}
MainWindow::~MainWindow()
{}
点击C-B,项目应该可以构建。
然后我们可以在Library::string()
实现中设置一个断点,以查看不仅代码被调用,而且调试器跨子项目工作。在"library.cpp
"中,单击"return "I come from the library";
"行号左侧灰色区域的。点击的地方会出现一个带有小沙漏的红色圆圈:这意味着设置了一个挂起的断点。
接下来按C-Y在调试器中启动项目。唯一可运行的子项目是应用程序,它将被自动选择为启动项目。
最终,当调试器读取符号文件并找出断点的位置时,断点圆将失去沙漏。此后不久,代码将停止在Library::string()方法中——它是从MainWindow构造函数调用的。按C-Y键继续执行app
.
主窗口现在会出现,I come from the library
文本在里面可见。该文本设置在MainWindow的构造函数中添加的标签上。
库和类之间没有链接。库的概念早在面向对象之前就出现了,c/c++的库格式中没有任何与类或命名空间有关的内容。
如果你使用的是静态库(不是DLL),那么链接器将只提取程序需要的那些函数,因此库的大小无关紧要。使用动态库(dll),你必须将整个dll打包,所以有理由只将类似的库打包到一个dll中——这就是为什么Qt将QtOpenGl.dll从QtGui.dll中分离出来——如果你不使用opengl,就不需要包含库。头文件的大小对完成的程序无关紧要——尽管非常大的头文件会导致编译速度变慢(除非你已经预编译了头文件)。
命名空间用于显示这些类一起工作,并避免与其他类冲突,因此我将使用单个命名空间为您编码/解码类。
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- EASTL矢量<向量<int>>连续的
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在
- 是numeric_limits&lt; int&gt; :: is_modulo从逻辑上矛盾
- opencv 2.4.7在iOS错误背景_segm.hpp #include&lt; list&gt;未找到
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- ///<评论></评论>在Visual Studio中