【问题标题】:how friend function has been implemented internally朋友功能是如何在内部实现的
【发布时间】:2015-04-14 10:43:47
【问题描述】:

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

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

请注意: 此问题与如何使用好友功能或好友功能的使用无关。

【问题讨论】:

  • 友元函数的运行时实现没有什么特别之处。它只是一种允许函数访问类的私有成员的编译时机制。
  • 感谢您的评论。 @JosephMansfield 我不明白你的意思,但我试图理解的编译时机制。你能放一些链接,以便我可以轻松参考。正如我列出的 V-table 和 V-ptr 也编译时修改,但我们知道编译时修改是如何发生的。
  • @Nihar 不,虚函数是一种运行时机制。它改变了编译的输出。正如您所说,可执行文件将创建 v-tables 等。 friend 函数不是这样的。它只是影响程序是否会实际编译。如果您编写的程序具有函数并编译该函数是否为friend,则添加friend 关键字对编译输出没有影响。
  • @Nihar 很难知道用什么来回答这个问题。编译器只是按照标准所说的对friend 关键字执行的操作。怎么做取决于编译器。
  • friend 的任何实现细节都将与 vtables 完全不同。这读起来就像“我想知道如何使用沙子,就像我们如何使用公理来证明定理一样”——这看起来很有意义,但前提是你不知道沙子、公理和定理是什么。对您的“喜欢”的任何类似回答都是一个巨大的延伸。我不知道你在问什么。

标签: c++ compiler-construction friend-function


【解决方案1】:

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

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

gcc 有一个函数is_friend(),定义在 friend.c 中,如果函数或类型是朋友,它基本上返回。下面是函数的相关代码:

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):编译器对每个类都有一个朋友列表,并迭代这个列表以确定一个函数是否是朋友(在编译时,课程。)。如果是,它只是授予访问权限。没有为此生成特殊代码:这是一个常规函数调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-24
    • 2010-10-11
    • 2010-10-11
    • 2015-09-29
    • 2011-11-27
    • 2011-04-17
    • 1970-01-01
    相关资源
    最近更新 更多