Доступ к функции друга, определенной в классе - PullRequest
40 голосов
/ 16 октября 2011

Есть такой код:

#include <iostream>

class A{

public:
    friend void fun(A a){std::cout << "Im here" << std::endl;}
    friend void fun2(){ std::cout << "Im here2" << std::endl; }
    friend void fun3();
};

void fun3(){
    std::cout << "Im here3" << std::endl;
}

int main() 
{  
    fun(A()); // works ok
    //fun2(); error: 'fun2' was not declared in this scope
    //A::fun2(); error: 'fun2' is not a member of 'A'
    fun3(); // works ok
} 

Как получить доступ к функции fun2 ()?

Ответы [ 2 ]

34 голосов
/ 16 октября 2011
class A{

public:
    friend void fun(A a){std::cout << "Im here" << std::endl;}
    friend void fun2(){ std::cout << "Im here2" << std::endl; }
    friend void fun3();
};

Хотя ваше определение fun2 действительно определяет «глобальную» функцию, а не члена, и делает ее friend из A в то же время, вы все ещеотсутствует объявление той же функции в самой глобальной области действия.

Это означает, что ни один код в этой области не имеет представления о существовании fun2.

Та же проблема возникает для fun, за исключением того, что Argument-Dependent Lookup может вступить во владение и найти функцию, потому что есть аргумент типа A.

Я рекомендую вместо этого определять ваши функции обычным способом:

class A {
   friend void fun(A a);
   friend void fun2();
   friend void fun3();
};

void fun(A a) { std::cout << "I'm here"  << std::endl; }
void fun2()   { std::cout << "I'm here2" << std::endl; }
void fun3();

Обратите внимание, что все работает (кроме fun3, потому что я его никогда не определял).

22 голосов
/ 16 октября 2011

Причина, по которой вы можете вызвать fun, заключается в том, что объявление друга внутри класса A делает его видимым только в зависимости от аргументов. В противном случае объявления друзей не делают функции, которые они объявляют, автоматически видимыми за пределами области видимости класса, где они появляются.

Вам необходимо добавить объявление в области имен или внутри main, чтобы сделать fun2 видимым в main.

1010 * Е.Г. *

void fun2();

fun3 виден внутри main, поскольку его определение (вне класса) также является объявлением, которое делает его видимым из main.

ИСО / МЭК 14882: 2011 7.3.1.2:

Имя друга не найдено ни в неквалифицированном поиске (3.4.1), ни в квалифицированном поиске (3.4.3), пока не будет предоставлено соответствующее объявление в этой области пространства имен (до или после определения класса, предоставляющего дружбу).

3.4.2 (поиск имени в зависимости от аргумента) / 4:

Любые дочерние функции области имен или шаблоны дружественных функций, объявленные в связанных классах, видны в их соответствующих пространствах имен, даже если они не видны во время обычного поиска (11.3).

...