Средство просмотра qml (для 4.8 и 5.0) реализовано так:
В .h (eader) имеем:
class QtQuick2ApplicationViewer : public QQuickView
{
Q_OBJECT
...
private:
class QtQuick2ApplicationViewerPrivate *d;
};
Затем в файле .CPP:
class QtQuick2ApplicationViewerPrivate
{
QString mainQmlFile;
friend class QtQuick2ApplicationViewer;
static QString adjustPath(const QString &path);
};
QtQuick2ApplicationViewer::QtQuick2ApplicationViewer(QWindow *parent)
: QQuickView(parent)
, d(new QtQuick2ApplicationViewerPrivate())
{
connect(engine(), SIGNAL(quit()), SLOT(close()));
setResizeMode(QQuickView::SizeRootObjectToView);
#ifdef Q_OS_ANDROID
engine()->setBaseUrl(QUrl::fromLocalFile("/"));
#endif
}
Почему используется friend
необходимо здесь? Я не вижу никакой причины, почему кто-то использовал бы friend
учебный класс. Есть ли реальная польза для занятий с друзьями (кроме экзотики, без которой кто-либо может жить)?
.час
#включают
class QtQuick2ApplicationViewer : public QQuickView
{
Q_OBJECT
public:
explicit QtQuick2ApplicationViewer(QWindow *parent = 0);
virtual ~QtQuick2ApplicationViewer();
void setMainQmlFile(const QString &file);
void addImportPath(const QString &path);
void showExpanded();
private:
class QtQuick2ApplicationViewerPrivate *d;
};
.CPP
#include "qtquick2applicationviewer.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtQml/QQmlEngine>
class QtQuick2ApplicationViewerPrivate
{
QString mainQmlFile;
friend class QtQuick2ApplicationViewer;
static QString adjustPath(const QString &path);
};
QString QtQuick2ApplicationViewerPrivate::adjustPath(const QString &path)
{
#ifdef Q_OS_UNIX
#ifdef Q_OS_MAC
if (!QDir::isAbsolutePath(path))
return QString::fromLatin1("%1/../Resources/%2")
.arg(QCoreApplication::applicationDirPath(), path);
#elif !defined(Q_OS_ANDROID)
const QString pathInInstallDir =
QString::fromLatin1("%1/../%2").arg(QCoreApplication::applicationDirPath(), path);
if (QFileInfo(pathInInstallDir).exists())
return pathInInstallDir;
#endif
#endif
return path;
}
QtQuick2ApplicationViewer::QtQuick2ApplicationViewer(QWindow *parent)
: QQuickView(parent)
, d(new QtQuick2ApplicationViewerPrivate())
{
connect(engine(), SIGNAL(quit()), SLOT(close()));
setResizeMode(QQuickView::SizeRootObjectToView);
#ifdef Q_OS_ANDROID
engine()->setBaseUrl(QUrl::fromLocalFile("/"));
#endif
}
QtQuick2ApplicationViewer::~QtQuick2ApplicationViewer()
{
delete d;
}
void QtQuick2ApplicationViewer::setMainQmlFile(const QString &file)
{
d->mainQmlFile = QtQuick2ApplicationViewerPrivate::adjustPath(file);
setSource(QUrl::fromLocalFile(d->mainQmlFile));
}
void QtQuick2ApplicationViewer::addImportPath(const QString &path)
{
engine()->addImportPath(QtQuick2ApplicationViewerPrivate::adjustPath(path));
}
void QtQuick2ApplicationViewer::showExpanded()
{
#if defined(Q_WS_SIMULATOR)
showFullScreen();
#else
show();
#endif
}
Друзья осматривают рядовые друзей. Вы уверены, что можете вообще обходиться без ограничений доступа, но как только вы используете его, дружелюбие помогает в интимных ситуациях.
class Me;
class You {
friend class Me;
private:
Home _home;
Car _car;
public:
void bar(Me my);
};
class Me {
Stuff _stuff;
public:
foo(You you) {
//If you consider me a friend
you._home.enter(); //I can enter your `private _home`
you._car.drive(); //I can drive your `private _car`.
}
};
void You::bar(Me my) {
my.stuff //this is an error because I don't consider you a friend so you can't touch my `private _stuff`.
}
Зная, что ты всегда можешь рассчитывать на меня, наверняка. Вот для чего нужны друзья. http://www.youtube.com/watch?v=xGbnua2kSa8
Но я думаю, что вы спрашиваете о классах друзей в C ++.
Весь смысл «объема» состоит в том, чтобы точно определить, кто что может видеть в другом классе. Вам не «нужны друзья» больше, чем «защищенные» или «частные», в том смысле, что вы можете сделать все в ваших классах общедоступными, и ваша программа будет успешно скомпилирована и запущена. Но идея состоит в том, чтобы установить и документировать именно то, что является общедоступным интерфейсом класса, и, таким образом, его нельзя изменить без учета влияния на другие классы и что является внутренней реализацией, которую можно свободно переработать или реорганизован без страха воздействия на другие классы.
Итак, смысл «друга» в том, чтобы сказать: «Эй, у меня есть этот класс X и этот другой класс Y. И вообще другим классам не нужно знать, как X выполняет свою работу. Но Y взаимодействует с какой-то низкоуровневой вещью в X, поэтому ему нужно это увидеть. Таким образом, я делаю Y другом X. Например, у меня есть класс Investor, у которого есть функция, которая (предположительно, среди прочего) имеет функцию для расчета общей суммы инвестиций клиента. В общем, другим классам не важно, как я делаю этот расчет: им просто нужно общее количество. Но теперь у меня есть класс TaxReporting, который должен знать, какая часть этого баланса находится в налогооблагаемых ценных бумагах, а какая — в необлагаемых налогом ценных бумагах. Может быть, я не хочу делать эти функции общедоступными, потому что информация конфиденциальна, и я хочу ограничить доступ в реальных условиях конфиденциальности. Чаще всего я не хочу делать это общедоступным, потому что вычисления сложны или подвержены частым изменениям, и я хочу строго контролировать доступ к ним классов, чтобы ограничить проблемы, возникающие при изменении ситуации. Поэтому я делаю TaxReporting с другом, чтобы он мог получить доступ к некоторым функциям, которые делают различие, не открывая их миру.
На практике, когда я занимался C ++, я редко пользовался друзьями. Но «редко» — это не «никогда». Если вы обнаружите, что говорите: «О, я должен сделать это публичным, чтобы этот другой класс мог его увидеть», тогда, возможно, вместо того, чтобы обнародовать это, вы должны подружиться.
«друг» очень полезен и то, что вы хотите использовать все время.
Типичные случаи использования:
У вас есть класс, который использует подклассы, где подклассу разрешено использовать частные функции класса, которому принадлежат подклассы:
class ManagedObject
{
public:
void doStuff() { mMgr->updateManager(); }
private:
Manager* mMgr;
};
class Manager
{
friend ManagedObject;
public:
ManagedObject* createManagedObject();
private:
void updateManager() { }
};
Так что в этом случае у вас есть класс, который создает и имеет дело с «managedObject». Всякий раз, когда этим объектом манипулируют, ему необходимо обновить объект, который его создал. Вы хотите, чтобы пользователи вашего класса знали, что им никогда не нужно вызывать «updateManager», и фактически выдают ошибку времени компиляции, если они это делают.
Другой распространенный случай — когда у вас есть функция, которая действует как член класса, но по какой-то причине не может быть членом класса. Примером является оператор<<, Если вы пишете свой собственный класс IO Stream, или если вы хотите создать систему сериализации, что оператор пользователя<<:
class serializedObject
{
public:
friend Serializer& operator<< ( Serializer& s, const serializedObject& obj );
protected:
u32 mSecretMember;
};
Serializer& operator<<( Serializer& s, serializedObject& obj )
{
serializer << obj.mSecretMember;
return s;
}
В этом случае функция сериализации не может быть членом serializedObject, но для ее сериализации необходимо взглянуть на внутренние элементы serializedObject. Вы увидите аналогичные схемы создания других операторов (например, сложение), где RHS оператора отличается от класса LHS
В Qt есть нечто, называемое «гарантией двоичной совместимости», что означает, что ваше приложение может работать на Qt4.8, 4.8.1 и 4.8.2 и так далее без перекомпиляции.
Для достижения этого vtable для объектов не может быть изменен. Итак, классы Qt пишутся с использованием идиомы «PIMPL» (указатель на реализацию).
Класс «Private» является частной реализацией открытого класса — это деталь реализации QtQuick2ApplicationViewer. Никто в мире не знает о частном классе, кроме общественного класса. Эти два класса глубоко переплетены дизайном. На самом деле, это действительно разные аспекты одного объекта, который был разделен на c ++ для достижения гарантии двоичной совместимости.
В этом контексте разумно, что частный класс может получить доступ к общедоступному классу.
2) В этом контексте quit
не является QApplication::quit()
, то есть slot
причины, но какой-то внутренний сигнал engine()
,