friend函数是如何在内部实现的



我们都在C++中使用过全局级和类级的友元函数。我试着在网上搜索内部好友功能是如何实现的。

"朋友"关键字做了什么操作。例如,我们知道v-ptr和v-table是如何在内部实现的,我正在寻找同样的答案。

请注意:这个问题与如何使用好友功能或使用好友功能无关

为了得到这个答案,我在gcc上搜索了一个非常旧的版本,因为它更小,更容易推理。最新版本或其他编译器中的实现可能完全不同。

搜索到的源文件可以在opensource.apple.com 上查看

gcc有一个函数is_friend(),在friend.c中定义,它基本上返回函数或类型是否是friend。以下是功能的相关代码:

int
is_friend (type, supplicant)
tree type, supplicant;
{
int declp;
register tree list;
tree context;
if (supplicant == NULL_TREE || type == NULL_TREE)
return 0;
/*
Comment added by me: The following defines are in tree.h
#define TREE_CODE(NODE) ((enum tree_code) (NODE)->common.code)
#define TREE_CODE_CLASS(CODE)    tree_code_type[(int) (CODE)]
This is expanded as:
declp = (tree_code_type[(int) (((enum tree_code) (supplicant)->common.code))] == 'd')
*/
declp = (TREE_CODE_CLASS (TREE_CODE (supplicant)) == 'd');
// That is, it will simply search the array for the code of the supplicant and check if it is a function declaration.
if (declp)
/* It's a function decl.  */
{
tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type));
tree name = DECL_NAME (supplicant);
tree ctype;
if (DECL_FUNCTION_MEMBER_P (supplicant))
ctype = DECL_CLASS_CONTEXT (supplicant);
else
ctype = NULL_TREE;
for (; list ; list = TREE_CHAIN (list))
{
if (name == FRIEND_NAME (list))
{
tree friends = FRIEND_DECLS (list);
for (; friends ; friends = TREE_CHAIN (friends))
{
if (same_type_p (ctype, TREE_PURPOSE (friends)))
return 1;
if (TREE_VALUE (friends) == NULL_TREE)
continue;
if (supplicant == TREE_VALUE (friends))
return 1;
/* With -fguiding-decls we are more lenient about
friendship.  This is bogus in general since two
specializations of a template with non-type
template parameters may have the same type, but
be different.  
Temporarily, we are also more lenient to deal
with nested friend functions, for which there can
be more than one FUNCTION_DECL, despite being the
same function.  When that's fixed, the
FUNCTION_MEMBER_P bit can go.  */
if ((flag_guiding_decls 
|| DECL_FUNCTION_MEMBER_P (supplicant))
&& same_type_p (TREE_TYPE (supplicant),
TREE_TYPE (TREE_VALUE (friends))))
return 1;
if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL
&& is_specialization_of (supplicant, 
TREE_VALUE (friends)))
return 1;
}
break;
}
}
}
else
/* It's a type.  */
{
// ...
}
if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
context = DECL_CLASS_CONTEXT (supplicant);
else if (! declp)
/* Local classes have the same access as the enclosing function.  */
context = hack_decl_function_context (TYPE_MAIN_DECL (supplicant));
else
context = NULL_TREE;
/* A namespace is not friend to anybody. */
if (context && TREE_CODE (context) == NAMESPACE_DECL)
context = NULL_TREE;
if (context)
return is_friend (type, context);
return 0;
}

基本上,它获取特定类型的朋友列表,并对其进行迭代,检查其中是否有任何一个与正在测试的函数相等。友元函数是通过使用在同一源文件中定义的类似函数添加到类型中的:add_friend()add_friends()用于类的所有成员函数,make_friend_class()用于类等。

我猜它在检查访问权限时(它可能会因为访问私人成员而对你大喊大叫),会使用这个函数来确定该函数是否有访问权限。

你的问题的答案是(至少对于这个旧版本的GCC):编译器为每个类都有一个朋友列表,并迭代这个列表来确定函数是否是朋友(当然是在编译时)。如果是,它只授予访问权限。没有为此生成特殊代码:这是一个常规函数调用。

最新更新