2015-04-14 5 views
1

Мы все использовали функцию друга как глобального уровня, так и уровня класса в C++. Я попытался найти через Интернет, как функция внутреннего друга была реализована.как функция друга была реализована внутренне

Какую манипуляцию выполняет ключевое слово «друг». Для примера мы знаем, как v-ptr и v-table реализованы внутри, я ищу такой же ответ.

Обратите внимание: Этот вопрос не связан, как использовать функцию друга или использование функции друга.

+4

Нет ничего особенного в реализации функции друга во время выполнения. Это всего лишь механизм времени компиляции, позволяющий функции доступа к закрытым членам класса. –

+0

Спасибо за комментарий. @JosephMansfield Я undrestand, что вы указываете, но механизм компиляции, который я пытаюсь понять. Можете ли вы поместить некоторую ссылку, чтобы я мог легко ссылаться. Поскольку я перечислил V-таблицу и V-ptr, также скопируйте изменение времени, но мы знаем, как происходит это изменение времени компиляции. – Nihar

+0

Дополнительные вопросы: Не зависит от компилятора? Что говорит стандарт C++? – TobiMcNamobi

ответ

4

Для целей этого ответа я искал очень старую версию на gcc, потому что она меньше и проще рассуждать. Внедрение в новейших версиях или в других компиляторах может быть совершенно иным.

Источник файлы искали можно посмотреть на opensource.apple.com

НКУ имеет функцию 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; 
} 

В основном, он получает список друзей определенного типа, и итерации через него, проверяя, если какое-либо из них равно функции тестируются. функция Friend добавлена ​​к типу, используя аналогичные функции, определенные в том же исходном файле: add_friend(), add_friends() для всех функций-членов класса, make_friend_class() для классов и т.д.

Я предполагаю, что он использует эту функцию, чтобы определить, , при проверке доступа (момент, когда он может кричать на вас для доступа к частному члену), если функция имеет доступ или нет.

Ответ на ваш вопрос (по крайней мере, для этой старой версии GCC): у компилятора есть список друзей для каждого класса и выполняется итерация этого списка, чтобы определить, является ли функция другом (во время компиляции, конечно.). Если это так, он просто предоставляет доступ. Для этого нет специального кода: это обычный вызов функции.

+0

благодарит @ Cássio Renan, это действительно очень полезно – Nihar