为什么我们需要在这里"friend"?(C++)

Why we need a "friend" here? (C++)

本文关键字:C++ friend 为什么 在这里 我们      更新时间:2023-10-16

QML Viewer(对于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类的原因。朋友类有任何真正用途(除了任何人可以不用的外来者都可以使用)吗?

.h #include

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中的一些低级事物互动,因此需要看到它。因此,我成为X的朋友。就像,我有一个投资者课程,其功能(大概是其他事项)具有计算客户投资总量的功能。通常,其他课程不应该关心我如何进行计算:他们只是想要总计。但是现在我有了一个租赁级别的班级,需要知道应纳税证券中的这种余额中有多少以及在非税收证券中有多少。也许我不想将这些功能公开,因为这些信息是机密的,我想限制出于现实世界中的隐私原因而限制访问。我经常不想将其公开,因为计算很棘手或经常发生变化,我想密切控制哪个类访问它以限制事物变化时造成的问题。因此,我成为朋友,以便它可以访问一些可以区分的功能,而无需向世界开放这些功能。

实际上,当我做C 时,我很少使用朋友。但是"很少"不是"永远"。如果您发现自己在说:"哦,我必须公开这堂课,以便其他班级可以看到",那么也许不是公开它,而是应该交朋友。

典型用例是:

您有一个使用子类的类

class ManagedObject
{
public:
   void doStuff() { mMgr->updateManager(); }
private:
   Manager* mMgr;
};
class Manager
{
   friend ManagedObject;
public:
   ManagedObject* createManagedObject();
private:
   void updateManager() { }
};

因此,在这种情况下,您有一个创建和处理"托管对象"的类。每当操纵此对象时,都需要更新创建它的对象。您希望您的班级用户知道他们不需要称呼" UpdateManager",实际上WAT即可产生编译时间错误。

另一个常见的情况是,当您具有像类成员一样起作用但不能出于某种原因成为班级成员的函数。一个例子是运营商&lt;&lt;。如果您编写自己的IO流类,或者要创建一个用户操作员&lt;&lt;:

的序列化系统
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; 
}

在这种情况下,序列化函数不能是序列化对象的成员,但是需要查看序列化对象的内部以序列化。您会看到类似的模式创建其他操作员(例如添加),其中操作员的RHS与LHS

in qt,有一种称为"二进制兼容性的保证",这意味着您的应用程序可以在QT4.8、4.8.1和4.8.2等方面运行,而无需重新编译。

为了实现这一目标,对象的VTable无法更改。因此,使用" PIMPL"(指向实现的指针)成语编写QT类。

"私人"类是公共类的私人实现 - 它是qtquick2applicationviewer的实现细节。除了公共阶级,全世界没有人知道私人班。这两个类别通过设计深深交织。实际上,它们实际上是单个对象的不同方面,该对象已被划分为C ,以实现二进制兼容性保证。

在这种情况下,私人类可以访问公共类是合理的。

2)在此上下文中, quit不是 QApplication::quit(),那是原因的 slot,而是 engine()的某些内部信号。