Какова цель файлов _p.h?

В исходных файлах Qt есть две версии файлов заголовков, такие как:

qxmlstream.h
qxmlstream_p.h

Почему существуют файлы _p.h?

3 ответа

Решение

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

Другими словами, кое-что, о чем может потребоваться знать несколько исходных файлов C в Qt, будет в приватных заголовочных файлах, если пользователям Qt не нужно будет знать о них.

Одним из примеров может быть настроенный распределитель памяти для вашей подсистемы. Возможно, вы знаете, что каждое выделение памяти, которое вы делаете, составляет 128 байт, тогда вы можете предоставить такой распределитель:

void * malloc128 (void) { ... }

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

Тогда ваш собственный код использует:

#include "mysubsystem_p.h"

в то время как пользователи вашего API используют:

#include "mysubsystem.h"

Qt необходимо поддерживать стабильный внешний интерфейс на уровне ссылок. Чтобы решить это, они используют следующий подход:

class MyClass {
public:
  size_t compatSize();
private:
  MyClassPrivate *data;
};


// implementation
struct MyClassPrivate {
  int someFieldThatCanChange;
};
size_t compatSize() { return (size_t)(data->someFieldThatCanChange); }

При этом изменение реализации не влияет на размер и структуру MyClass, И вы все еще можете добавлять новые поля или удалять старые.
Другой подход заключается в использовании "интерфейсов" (абстрактных классов), фабрик и виртуальных функций для каждого метода, что, как мне кажется, приведет к более медленному коду.

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

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

Например, вместо:

class MyClass
{

public:
    MyClass();
    ~MyClass();

    QVariant getValue1();
    QVariant getValue2();
    QVariant getValue3();

private:
    QVariant m_Value1;
    QVariant m_Value2;
    QVariant m_Value3;
};

Мы могли бы иметь следующее

class MyClass
{

public:
    MyClass();
    ~MyClass();

    QVariant getValue1();
    QVariant getValue2();
    QVariant getValue3();

private:
    friend class MyClassPrivate;
};

где MyClassPrivate определяется следующим образом

class MyClassPrivate 
{

public:
    MyClassPrivate ();
    ~MyClassPrivate ();

    QVariant m_Value1;     
    QVariant m_Value2;
    QVariant m_Value3;
};

Другими словами, все члены частного класса, следовательно, "экспортируются" в общедоступное определение частного класса.

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

Другие вопросы по тегам