Каков рекомендуемый метод для создания библиотеки с несколькими классами? - PullRequest
3 голосов
/ 16 января 2012

Я относительно новичок в C ++ (предыдущий опыт работы с Python и баловство в Java), и я пишу небольшую программу в качестве ознакомительного проекта.Как часть программы я пишу класс для декодирования некоторых данных и в конечном итоге напишу аналогичный, который будет выполнять кодирование.Я уверен, что этот код я буду использовать довольно часто, и подумал, что было бы интересно создать библиотеку как часть проекта.У меня вопрос: что считается наилучшей практикой для создания библиотеки?

Редактировать: (Пересмотрено)

Задав этот вопрос, я понял, что не знаю, чего не знаю.Я провел еще несколько исследований, и это должно помочь сделать мой вопрос более конкретным:

  • Я занимаюсь разработкой в ​​Qt Creator.Так что подробности, относящиеся к Qt, были бы полезны, но не обязательны.
  • Я создал новый проект статической библиотеки в Qt (MyCodec), в котором в настоящее время определен один класс с именем MyDecoder.
  • Asбиблиотека, я предполагаю, что для добавления MyEncoder я просто создаю другой файл класса / заголовка.
  • Что происходит дальше, когда я не уверен.Я просто собираю библиотеку?Насколько я понимаю, он создаст (в Windows) файл .lib и .h.Есть ли что-то, что я должен сделать до этого шага?Существуют ли варианты, которые будут влиять на то, как я с ним взаимодействую?
  • Нужно ли просто включить этот файл заголовка в мою программу для доступа к обоим классам, которые я написал?
  • Я нашел много ответов при добавлениифайл .lib для проекта в Qt, поэтому мне эта информация не нужна.

Оригинальный вопрос: (для контекста)

Моя первоначальная мысльв том, что было бы наиболее удобно создать MyLib, включающую в себя классы MyEncoder и MyDecoder.

  • Если бы я сделал это таким образом, я бы просто объявил оба класса в заголовке?

  • Я хотел бы создать из этой библиотеки DLL для мобильности и опыта.Я уверен, что есть много информации о создании и использовании DLL (что не является предметом этого вопроса), но если есть особенно хорошее руководство (для Qt), пожалуйста, передайте его.

  • Я предполагаю, что было бы лучше использовать отдельные пространства имен для MyEncoder и MyDecoder для этой реализации в сравнении с одним пространством имен для MyLib?

Я вижу один компромиссэтот метод является размером приложения, так как включение MyLib.h будет включать код для кодера и декодера (если кодер и декодер были отдельными приложениями).Предполагается, что я не использую DLL.

Я предполагаю, что получаю:

  • Какие методы доступны (и рекомендуются)?
  • ЧтоКаковы компромиссы каждого?
  • Где я могу найти документацию (учебные пособия / примеры) по этой конкретной теме?Мои усилия по поиску не принесли много результатов.

Если это поможет быть более конкретным, я делаю свою разработку, используя Qt 4.7.4 в Qt Creator.

Ответы [ 3 ]

6 голосов
/ 16 января 2012

Одна из "лучших практик" в 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, поэтому я не могу говорить об этом авторитетно или о том, как получить доступ к соответствующим опциям. Но, как правило, вы хотите иметь как минимум 2 версии вашей библиотеки; отладочная версия и версия выпуска. Если ваша библиотека использует библиотеки Qt, то, когда приложение ссылается на отладочную версию вашей библиотеки, они должны будут иметь отладочную версию общих библиотек Qt в своем пути, и если они ссылаются на вашу версию выпуска, им потребуется иметь выпускную версию библиотеки Qt.

Возможны также варианты статической ссылки на стандартные библиотеки времени выполнения C ++ или динамической ссылки на библиотеки DLL.

Но, по сути, да, вы просто собираете библиотеку, а затем приложение, которое ее использует, свяжет библиотеку с исполняемым файлом.

Должен ли я просто включить этот заголовочный файл в мою программу для доступа к обоим классы, которые я написал?

Вы включаете файл заголовка и ссылку на файл .lib. Это все, что вам нужно сделать.

4 голосов
/ 31 мая 2012

Это относится к Qt Creator 2.4.1.

Прежде всего, чтобы использовать и отлаживать вашу библиотеку, вам нужно иметь иерархический топ-проект с двумя подпроектами: один для библиотеки и одиндля приложения, которое его использует.Таким образом, Creator будет перестраивать все, что было изменено до запуска приложения - таким образом, если вы измените исходные файлы библиотеки, библиотека будет перестроена автоматически , а также приложение будет перекомпоновано.

Я покажу, шаг за шагом, как создать три необходимых проекта (библиотека, приложение и верхний проект), в итоге получим готовое к отладке, минимальное приложение и библиотеку.Вы можете легко добавить больше библиотек, выполнив те же действия.

Создание проектов

  1. Создание папки для ваших проектов.

  2. Top Project

    • File->New File or Project, Other Project, Subdirs Project, Choose
    • Назовите проект top и поместите его в папку, созданную на шаге 1.
    • Щелкните по«Готово и добавление подпроекта»
  3. Библиотечный проект - новое окно проекта появляется при переходе по ссылке на предыдущем шаге.

    • Other Project, C++ Library, Choose
    • Тип: измените на Статически связанную библиотеку.
    • Назовите проект library и поместите его в папку top, созданную на предыдущем шаге.Эта папка должна быть уже выбрана по умолчанию для вас.
    • Нажмите, выберите модуль QtCore, который будет использоваться проектом библиотеки, оставьте все остальное по умолчанию.
  4. Application Project - щелкните правой кнопкой мыши проект top на панели Projects (не на top.pro)

    • Qt Widget Project, Qt Gui Application, Choose
    • Назовите проект app и введитеон находится в папке top, созданной на шаге 2. Эта папка должна быть уже выбрана по умолчанию для вас.
    • Нажмите, оставьте все в настройках по умолчанию.

Теперь у вас должен быть готовый top проект, который имеет app и library в качестве подпроектов.Нажмите CB (Ctrl-B или Command-B, в зависимости от вашей платформы), чтобы построить его.Сборка должна пройти без ошибок.

Установка зависимостей

Связывание с библиотекой

Подпроект app еще не использует нашу библиотеку.Чтобы иметь ссылку app с нашей библиотекой:

  1. Щелкните правой кнопкой мыши app на панели "Проекты" ( не в app.pro), выберите Add Library...

  2. Выберите Internal Library, Продолжить

  3. library является единственным выбором и уже выбран.Нажмите до конца.

Проект app теперь статически связан с library.Измените любой файл в проекте app (будет произведено изменение пробела), чтобы вызвать сборку, затем нажмите CB для сборки.Сборка должна пройти через ОК.

Добавление зависимости верхнего уровня в библиотеку

Подпроект app будет перестроен, если библиотека будет изменена, но нет ничего, что могло бы гарантировать, что makeСистема сначала создаст подпроект библиотеки, прежде чем приступить к сборке приложения.Такая информация содержится в файле проекта верхнего уровня top.pro.

Откройте top.pro и добавьте строку CONFIG += ordered.Файл должен выглядеть следующим образом:

TEMPLATE = subdirs

SUBDIRS += \
    library \
    app

CONFIG += ordered

Убедитесь, что SUBDIRS правильно упорядочены: библиотека идет первой перед app.Если порядок неправильный, вы можете перемешать записи в правильном порядке.Обратная косая черта \ является символом продолжения строки. После \!

не должно быть пробелов. Сохраните файл (CS), щелкните правой кнопкой мыши проект top и выберите «Перестроить проект« вверху ».Сборка должна завершиться без ошибок.Предупреждения в порядке.

Выбор сборки

В левой нижней панели Qt Creator есть панель с кнопкой сборки (молоток), кнопкой запуска (треугольник), кнопкой отладки (треугольник с ошибкой), селектором сборки ( портативный компьютер с top именем проекта над ним и конфигурацией elided build ниже. Нажмите на селектор сборки и убедитесь, что вы выбрали Build, заканчивающийся Debug. Эта сборка настроена для создания отладочных символов, необходимых для ее запуска в отладчик. Он понадобится нам позже.

Реализация библиотеки

Теперь мы добавим некоторый код в класс Library, который был создан для нас Qt Creator. Откройте файлы library.h и 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, код должен перестраиваться без ошибок.

Реализация приложения

Теперь давайте используем библиотечный API из нашего app. Откройте файлы 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.

2 голосов
/ 16 января 2012

Нет связи между библиотекой и классами.Концепция библиотек появилась задолго до ОО, и в формате c / c ++ нет ничего общего с классами или пространствами имен.

Если вы используете статические библиотеки (не DLL), то компоновщик будетвытащите только те функции, которые нужны программе, и поэтому размер библиотеки не имеет значения.С динамическими библиотеками (dll) вы должны отправить целую библиотеку DLL, поэтому есть причина упаковывать в библиотеку только похожие библиотеки - вот почему Qt имеет, например, QtOpenGl.dll отдельно от QtGui.dll - если вы не используетеВ opengl нет необходимости включать библиотеку.Размер файла заголовка не имеет значения для готовой программы - хотя очень большие файлы заголовка приведут к более медленной компиляции (если у вас нет предварительно скомпилированных заголовков).

Пространство имен используется, чтобы показать, что эти классы работают вместеи чтобы избежать столкновений с другими классами, поэтому я бы использовал единственное пространство имен для кодирования / декодирования классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...