2012-10-25 85 views
2

的QML查看器(4.8和5.0)被实现这样的:为什么我们需要一个“朋友”在这里? (C++)

在.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 
} 
+0

你在这里有两个完全不相关的问题。请不要这样做。每个问题发布一个问题,以及问题。 (即你应该编辑你的帖子,只留下其中一个问题。) – Mat

回答

6

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

+3

好吧,友谊是不可交换的,但我认为你只是写了lulz +1 –

+0

那么,具体关于友谊的方向会毁了散文,所以我只是避免显然是错误的;) –

+0

我不让我的朋友检查我的私处。 –

-1

2)在这方面quit不是QApplication::quit(),也就是slot的原因,但有些内部信号为engine()

1

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

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

“范围”的重点是准确定义谁可以看到另一个类中的内容。除了需要“受保护”或“私人”以外,您不需要“朋友”,因为您可以将所有课程中的所有内容公开化,并且您的程序可以成功编译和运行。但是,这个想法是建立 - 并记录 - 什么是一个类的公共接口,因此在不考虑对其他类的影响的情况下不能改变,什么是内部实现,可以自由地重新工作或无需担心影响其他班级而重新组织。

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

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

0

“朋友”是超级有用的,你想一直使用的东西。

典型的使用情况是:

你有一个使用在子类中被允许使用拥有该子类的私有函数子类:

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

private: 
    Manager* mMgr; 
}; 

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

private: 
    void updateManager() { } 
}; 

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

另一种常见情况是,当您有一个类似于类成员的函数,但由于某种原因不能成为类成员时。一个例子是运营商< <。如果你写你自己的IO流类,或者如果你想创建一个序列化系统用户操作< <:

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

+0

这不会破坏封装的目的吗?没有更好的方法来达到同样的效果吗? 你有什么想法为什么在我上面的例子中使用一个朋友类。我没有看到它存在的任何理由。 – Zingam

+0

我无法从代码片段中知道。 ApplicationViewerPrivate都是私有的。我没有在那里看到构造函数。可能是构造函数是私有的,应用程序查看器需要是访问构造函数的朋友。隐藏只能由类工厂构造的类的构造函数也是常见模式。防止除了朋友类之外的任何人实例化对象。 –

+0

此外 - 朋友不会'封锁'封装 - 但启用它。一般来说,你想把所有东西都锁定为const和private/protected,然后只允许需要允许的东西,但只公开一些成员,或者只给某个类锁定一些类,而这些类全部被锁定。 –

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

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

为了达到这个目的vtable不能改变。所以,Qt类是使用“PIMPL”(指向实现)成语编写的。

“Private”类是公共类的PRIVATE实现 - 它是QtQuick2ApplicationViewer的实现细节。全世界没有人知道除公共课以外的私人课。这两个课程由设计深深交织在一起。实际上,为了实现二进制兼容性保证,它们是单独对象的真正不同的方面,这些对象已经通过C++明智分区。

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

相关问题