【问题标题】:How come forward declaration is not needed for friend class concept?朋友类概念如何不需要出面声明?
【发布时间】:2012-03-27 13:43:59
【问题描述】:

我最近刚刚了解了 C++ 中的 friend class 概念(我用谷歌搜索了一下,但这个 answer 让我发笑,直到我想起最重要的部分),我正在尝试将把它放到我现在正在做的项目中。简洁的问题最后被挑出来,但总的来说,我对我的工作代码中完全缺乏前向声明感到困惑。

我所有的类都通过(子)文件夹分开,每个类都放在一个单独的 .h.cpp 文件中,但这应该足以获得一个对依赖的感觉:

// FE.h - no implementations - no .cpp file
class FE
{
    private:
       virtual void somePrivateFunc() = 0;
    // 90% virtual class, interface for further implementations
    friend class TLS;
};

// DummyFE.h
#include "FE.h"
class DummyFE :: public FE {
    /* singleton dummy */
    private:
        // constructor
    public:
        static DummyFE& instance();
};
// DummyFE.cpp
#include "DummyFE.h"
// all Dummy FE implementation

// ImplFE.h
#include "FE.h"
class ImplFE :: public FE { /* implemented */ };
// ImplFE.cpp
#include "FE.cpp"
// all Impl FE implementations


// SD.h - implements strategy design pattern
//        (real project has more than just FE class in here)
#include "FE.h"
#include "DummyFE.h"
class SD
{
    private:
        FE &localFE;
    public:
        SD(FE &paramFE = DummyFE::instance());
    // ... and all the other phun stuff ... 
    friend class TLS;
};
// SD.cpp - implementations
# include "SD.h"
/* SD implemented */

// TLS.h - implements strategy design pattern
           (on a higher level)
#include SD.h
class TLS{
    private:
        SD *subStrategy;
    public:
        void someFunctionRequiringFriendliness();
}

// TLS.cpp - implementations
#include "TLS.h"
void TLS::someFunctionRequiringFriendliness(){
    this->subStrategy->localFE.somePrivateFunc(); // ok!
}

现在,我已经让所有这些都与所有依赖项一起实际编译(必须在最后将其写到类图中才能使其工作),但现在可以了。实际上让我困惑的事实是不需要前向声明。我知道之前的前向声明,为了以防万一,我用this answer 刷新了我的记忆。

所以,为了清楚起见,我的问题: 将class TLS 声明为朋友时,为什么不需要明确的前向声明?这是否意味着 friend class 声明本身就是一个前向声明?对我来说,直觉上,这里缺少一些东西......而且由于它可以正常编译和工作,有人可以帮助纠正我的直觉吗? :D

PS 很抱歉对这个问题和一堆代码进行了如此冗长的介绍。请不要评论我的代码概念 - 朋友们在这里很好,我很确定这对我当前的项目是正确的(从这个骨架中很难看出)。我只是想知道为什么在任何地方都不需要前向声明。

【问题讨论】:

    标签: c++ class forward-declaration friend-class


    【解决方案1】:

    你说得对,朋友声明有点像前向声明。

    以下编译:

    class A;
    class B
    {
       friend A;
    };
    

    class B
    {
       friend class A;
    };
    

    这不是:

    class B
    {
       friend A;
    };
    

    实际上前向声明class A 的不是friend 声明,而是class 关键字。这就是为什么第二个例子不起作用的原因,因为它不知道A 是什么。如果你事先声明A,就像在第一个sn-p中一样,它可以将A解析为类声明。

    I stand corrected.

    【讨论】:

    • 嗯。奇怪的。我刚刚遇到你说的在我的代码版本中编译的情况(这反映在 FE 不转发声明 TLS 或根本不包含它的事实) - 它有效!这就是让我困惑的地方!啊,而且,我刚刚注意到你使用了语法“friend A”而不是“friend class A”。您能否进一步扩展,我是否不小心将转发和朋友声明合并为一个?
    • 注意:第一个 sn-p 不会在 C++03 中编译(对于那些还不能使用 C++11 的人)。第二个 sn-p 不能用 g++4.5 或 clang++3.0 编译(即使在 C++11 模式下)。
    • @Luchian 我很困惑你是如何编译你的第二个例子的?这促使我提出这个问题,这似乎表明您的第二个示例不应该编译:stackoverflow.com/questions/14114956/…
    • @JaredC 很有趣,非常感谢您指出这一点。你每天都会学到新东西:)
    【解决方案2】:
    friend class TLS;
    

    这种语法本身的声明,这就是为什么您不需要额外的先前类型声明的原因。请注意,friend 声明与封闭命名空间中的声明略有不同(特别是对于函数)。

    特别是,除非在封闭的命名空间中也有声明,否则在 friend 声明中声明的函数只能通过参数相关查找找到(并且不能在类之外定义)。类也是如此,除非在命名空间级别也有声明,否则这样声明的类型在将其声明为友元的类之外将不可用。

    class B {
       friend class A;
    };
    //A foo();    // Error: A is not declared here!
    class A;
    A foo();      // Fine
    

    【讨论】:

    • 我只是想知道为什么我不需要在FESD 中明确声明TLS,但这是很多新信息。您的建议(在另一个类的主体中声明类型 only)可能会用于实现类的内部实用功能或类似功能?
    • @penelope:我认为这只是查找执行方式的副作用。关于类型,我没有考虑太多,这似乎意味着有一个类型 A 可以访问这个类,没有别的(即你不能使用 A 作为正确的类型甚至在B)。但是在函数的情况下,特别是如果你在类定义中定义函数,它会影响查找。
    【解决方案3】:

    前向声明不需要在文件顶部如下

    class A;
    class C;
    class D;
    class B
    {
       A* a;
       C* c;
       D* d;
    };
    

    相同
    class B
    {
       class A* a;
       class C* c;
       class D* d;
    };
    

    推荐的朋友语法只是使用后者

    【讨论】:

    • 对于友元声明,它在 C++03 中不是推荐而是必需,在 C++11 中的含义略有不同( where 和friend class X 不能用来引用模板参数)
    【解决方案4】:

    这是否意味着朋友类声明是转发 自己声明?

    是的

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多