被通告扼杀的朋友功能包括

Friend function massacred by circular includes

Class A 是 class B.

实例的唯一实例化器和容器

因此,将 class B 的构造函数设为私有似乎是个好主意,并且仅由 class B 中声明的友元函数调用,并且在 class A.

中定义

文件A.h(编辑:包含在class B 中定义的枚举)

#ifndef   A_H
#define   A_H

#include "B.h"

using namespace std;

class A
{   public:
    A();
    shared_ptr<B> CreateBInstance( const B::ENUM_STANDARD_COLORS );
    shared_ptr<B> CreateBInstance( const string );  // Custom color

    private:
    unique_ptr<map<int, shared_ptr<B>>> UPTR__BInstancesMap;
}
#endif

文件B.h(编辑:包含在class B 中定义的枚举)

#ifndef   B_H
#define   B_H

#include "A.h"  // Causes chaos

using namespace std;

class B
{   public:
    enum class ENUM_STANDARD_COLORS : unsigned int
    {   ...     // ~70 standard colors
    };

    private:
    B();

    friend
    shared_ptr<B> A::CreateBInstance( const ENUM_STANDARD_COLORS );

    friend
    shared_ptr<B> A::CreateBInstance( const string );   // Custom color
}
#endif

Class A 需要 class B 的完整声明 (#include) for shared_ptr<B>.

Class B 需要为友元函数声明一些 class A。 一个简单的前向声明导致错误:

invalid use of incomplete type 'struc A'

在友元函数声明处。

完整声明 (#include) 更糟糕:

error: prototype for 'std::shared_ptr A::CreateInstance()' does not match any in class 'A'

(但确实如此!)在友元函数声明处。
而且,因为 class B 现在坏了:

error: 'B' was not declared in this scope
error: template argument 1 is invalid

出现在 class A 以及 classes FG 中每次提到 B(等.) 其中#include class B 供自己使用 shared_ptr<B>.
而且,因为 classes FG 现在也被破坏了:

error: 'F' was not declared in this scope
error: template argument 1 is invalid>
error: 'G' was not declared in this scope
error: template argument 1 is invalid

出现在 class A 中每次提到 FG 时。

不幸的是,包含守卫不会阻止循环包含。

有没有办法让这个好友功能起作用?我从来没有一次犯过这么多错误!

在A头文件中,你可以简单地告诉编译器存在一个类型B,它需要在链接时寻找它。为此,请替换

#include "B.h" 

来自

class B;

Class A requires a full declaration (#include) of class B for shared_ptr<B>.

不,前向声明在 A.h 中就足够了。 shared_ptr (and unique_ptr) 不需要 class B 是 return 类型声明的完整类型 [1] 和 class 数据成员声明。

文件A.h

#ifndef   A_H
#define   A_H

class B;  // forward declaration

using namespace std;

class A
{   public:
    A();
    shared_ptr<B> CreateBInstance();

    private:
    unique_ptr<map<int, shared_ptr<B>>> UPTR__BInstancesMap;
};
#endif

[1] "regular" 类型 T 不是 shared_ptr.

也是如此

让 class A 成为 class B 的朋友消除了循环包含(如上面 songyuanyao 的回答下的评论中所述),但我不喜欢给 A 太多访问 B 的权限。

我想我想出了一个更好的方法,使用继承。如果这个 friend-limited-by-inheritance 工厂模式有名字,那会很高兴。否则很高兴知道我在这里是不是在玩火。

文件A.h

#ifndef   A_H
#define   A_H

#include "B.h"          // The more compelling reason for including B.h is that
                        // classes A thru Z comprise a static library, requiring
                        // only the inclusion of A.h to be used.  B.h through Z.h
                        // must be included directly or indirectly in A.h so that
                        // the caller knows all of the library's public functions.

using namespace std     // Makes these examples easier to read.

class A
{   public:
    A();
    shared_ptr<B> CreateBInstance( const B::ENUM_STANDARD_COLORS );
    shared_ptr<B> CreateBInstance( const string );  // Custom color

    private:
//  Please excuse my standards-defying variable names
    unique_ptr<map<int, shared_ptr<B>>> UPTR__BInstancesMap;
}
#endif

文件A.cpp

#include   "A.h"
#include   "BFactory.h"

...
    shared_ptr<B> A::CreateBInstance( const B::ENUM_STANDARD_COLORS enum__StandardColor )
    {   unsigned int  uint__BInstancesMapIndex = UPTR__BInstancesMap->size();
        shared_ptr<B> sptr__BInstance          = BFactory::CreateBInstance( uint__BInstancesMapIndex, enum__StandardColor );
        UPTR__BInstancesMap->insert( uint__BInstancesMapIndex, sptr__BInstance );
        return sptr__BInstance;
    }

    shared_ptr<B> A::CreateBInstance( const string str___CustomColor )
    {   unsigned int  uint__BInstancesMapIndex = UPTR__BInstancesMap->size();
        shared_ptr<B> sptr__BInstance          = BFactory::CreateBInstance( uint__BInstancesMapIndex, str___CustomColor   );
        UPTR__BInstancesMap->insert( uint__BInstancesMapIndex, sptr__BInstance );
        return sptr__BInstance;
    }
...

文件B.h

#ifndef   B_H
#define   B_H

using namespace std             // Makes these examples easier to read.

class B
{   public:
    enum class ENUM_STANDARD_COLORS : unsigned int
    {   ...                     // ~70 standard colors
    };

//  virtual                     // BFactory cannot be instantiated; it needs no destructor
    ~B();

    protected:
    static unique_ptr<B> CreateBInstance( const unsigned int, const ENUM_STANDARD_COLORS );
    static unique_ptr<B> CreateBInstance( const unsigned int, const string );   // Custom color

    private:
    B( const unsigned int );    // Eliminates default constructor, therefore BFactory cannot
                                // call B::B(); therefore the compiler does not generate
                                // BFactory::BFactory(); therefore BFactory (and BFactory.o)
                                // is empty; it doesn't even need a cpp file.
}
#endif

文件B.cpp

#include "B.h"
...
   unique_ptr<B> B::CreateBInstance( const unsigned int uint__BInstancesMapIndex, const ENUM_STANDARD_COLORS enum__StandardColor )
   {   unique_ptr<B> uptr__BInstance = unique_ptr<B>( new B( uint__BInstancesMapIndex ) );
       uptr__BInstance->SetColor( enum__StandardColor );
       return uptr__BInstance;
   }

   unique_ptr<B> B::CreateBInstance( const unsigned int uint__BInstancesMapIndex, const string               str___CustomColor   )
   {   unique_ptr<B> uptr__BInstance = unique_ptr<B>( new B( uint__BInstancesMapIndex ) );
       uptr__BInstance->SetColor( str___CustomColor   );
       return uptr_BInstance;
   }
...

文件BFactory.h

#ifndef   BFactory_H
#define   BFactory_H

#include  "B.h"

class BFactory : private B          // Make sure anything inherited from B becomes private.
{   friend class A                  // Friend declaration moved from class B.
};

#endif

更改摘要:
1) Class A不再是class B的好友
2) Class B 的工厂函数是受保护的,所以 BFactory 将继承它们,并且是静态的,这样我们就不需要 BFactory 的实例来调用它们。
3) Class BFactory 是 B 的空子class,没有构造函数、析构函数或局部成员;它只是继承了 B 的工厂函数,并将 class A 声明为友元。
4) Class A 现在调用BFactory 中的静态函数来获取B 的实例,而不是调用B 中的私有函数。

结果是只有 Class A 可以访问 class B 的静态工厂函数,而 class BFactory 不能用于其他任何事情——据我所知.