为什么我们需要一个“朋友”? (C ++)

时间:2012-10-25 14:55:33

标签: c++ qt qml qt-quick friend-class

qml查看器(适用于4.8和5.0)实现如下:

在.h(读者)我们有:

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
}

6 个答案:

答案 0 :(得分:6)

朋友检查朋友的私处。你肯定可以没有访问限制,但一旦你使用它,友好有助于亲密的情况。

答案 1 :(得分:2)

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`.
}

答案 2 :(得分:1)

知道你总是可以依靠我。这就是朋友的作用。 http://www.youtube.com/watch?v=xGbnua2kSa8

但我想你是在问C ++中的朋友课。

“范围”的重点是确切地定义谁可以看到另一个类中的内容。除了你需要“受保护”或“私人”之外你不需要“朋友”,因为你可以将所有课程中的所有内容公开,并且你的程序将成功编译和运行。但是这个想法是建立 - 并且记录 - 究竟什么是类的公共接口,因此如果不考虑对其他类的影响就不能改变,什么是内部实现,可以自由地重新编写或者重新组织,不用担心影响其他课程。

所以“朋友”的意思是说:嘿,我有这个类X,还有其他类Y.而且一般来说其他类不需要知道X如何去做它的工作。但Y与X中的某些低级事物交互,所以它需要看到它。因此,我让Y成为X的朋友。就像,我有一个投资者类,其功能(可能在其他方面)具有计算客户投资总额的功能。一般来说,其他课程不应该关心我如何进行计算:他们只想要总数。但现在我有一个TaxReporting课程,需要知道应税证券中有多少余额,以及非应税证券中有多少。也许我不想公开这些功能,因为这些信息是保密的,我想限制真实世界隐私的访问。更常见的是,我不想公开它,因为计算很棘手或经常变化,我想要严格控制哪些类访问它以限制事情发生变化时引起的问题。所以我让TaxReporting成为朋友,这样它就可以访问一些能够区分的函数,而无需向世界开放。

在实践中,当我做C ++时,我很少使用朋友。但“很少”不是“从不”。如果你发现自己说:“哦,我必须公开这个,这样其他一个班级才能看到它”,那么也许不应该公开你应该交朋友。

答案 3 :(得分:0)

“朋友”非常实用,是您想要一直使用的东西。

典型用例是:

您有一个使用子类的类,其中允许子类使用拥有子类的类的私有函数:

class ManagedObject
{
public:
   void doStuff() { mMgr->updateManager(); }

private:
   Manager* mMgr;
};

class Manager
{
   friend ManagedObject;
public:
   ManagedObject* createManagedObject();

private:
   void updateManager() { }
};

所以在这种情况下,你有一个创建和处理“managedObject”的类。每当操作此对象时,它都需要更新创建它的对象。您希望类的用户知道他们不需要调用“updateManager”,实际上如果他们这样做就会生成编译时错误。

另一个常见的情况是,当你有一个类似于类成员的函数但由于某种原因不能成为类成员。一个例子是运算符&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; 
}

在这种情况下,序列化函数不能是serializedObject的成员,但需要查看serializedObject的内部序列来序列化它。您将看到类似的模式,您创建其他运算符(如加法),其中运算符的RHS与LHS不是同一类

答案 4 :(得分:0)

在Qt中,有一种称为“二进制兼容性保证”的东西,这意味着您的应用程序可以针对Qt4.8,4.8.1和4.8.2等运行而无需重新编译。

为了实现这一目标,对象的vtable无法改变。因此,Qt类是使用“PIMPL”(指向实现的指针)成语编写的。

“Private”类是公共类的PRIVATE实现 - 它是QtQuick2ApplicationViewer的实现细节。除了公共课外,全世界没有人知道私人班级。这两个类与设计密切相关。实际上,为了实现二进制兼容性保证,它们实际上是单个对象的不同方面,这些对象已经被c ++划分。

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

答案 5 :(得分:-1)

2)在此背景下,quit不是QApplication::quit(),而是原因slot,而是engine()的一些内部信号。