创建包含多个类的库的推荐方法是什么?< / h1 >

What is the recommended method for creating a library with multiple classes?

本文关键字:gt lt h1 是什么 方法 包含多 创建      更新时间:2023-10-16

我对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将在运行应用程序之前重新构建更改的所有内容——因此,如果您更改了库源文件,库将自动重新构建以及应用程序将被重新链接。

我将一步一步地展示如何创建所需的三个项目(库、应用程序和顶部项目),最终得到一个可构建、可调试的最小应用程序和库。您可以按照相同的步骤轻松地添加更多的子库。

创建项目

  1. 为你的项目创建一个文件夹

  2. 高级项目

    • File->New File or Project, Other Project, Subdirs Project, Choose
    • 将项目命名为top,并将其放入步骤1中创建的文件夹中。
    • 点击"完成"添加子项目">
  3. Library Project -新项目窗口从上一步点击进入。

    • Other Project, C++ Library, Choose
    • 类型:改为静态链接库
    • 将项目命名为library,并将其放在前面创建的top文件夹中的一步。这个文件夹应该是默认选中的。
    • 点击通过,选择QtCore模块将被库项目使用,其余一切保持默认值
  4. 应用程序项目-右键单击项目窗格中的top项目(不在top.pro上)

    • Qt Widget Project, Qt Gui Application, Choose
    • 将项目命名为app并将其放入步骤2中创建的top文件夹中。这个文件夹应该是默认选中的。
  5. 点击完成,保持默认设置。

你现在应该有一个可构建的top项目,applibrary作为子项目。按C-B (Ctrl-B或Command-B,取决于您的平台)来构建它。构建过程应该没有错误。

设置依赖

链接到图书馆

app子项目还没有使用我们的库。将app链接到我们的库:

  1. 右键单击项目窗格中的app(而不是app.pro中的),选择Add Library...

  2. 选择Internal Library, Continue

  3. 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.cppmainwindow.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,就不需要包含库。头文件的大小对完成的程序无关紧要——尽管非常大的头文件会导致编译速度变慢(除非你已经预编译了头文件)。

命名空间用于显示这些类一起工作,并避免与其他类冲突,因此我将使用单个命名空间为您编码/解码类。