проблема с дружественной функцией

343
26 ноября 2016, 18:54

Я новичек в С++, объясните пожалуйста, почему не отрабатывает дружественная функция в main? Имеется:

class myClass {
private:
    int i,j;
public:
    myClass();
    virtual ~myClass();
    friend void myFunc();
};

В main() такой код:

#include "myClass.h"
int main(int argc, char *argv[]) {
myClass a;
myFunc();
return EXIT_SUCCESS;
}

В результате ошибка:

'myFunc' was not declared in this scope

Дико извиняюсь, заранее спасибо за помощь!

Answer 1

Компилятор действительно не видит объявление функции, если она не объявлена вне класса, и не имеет место зависящий от аргумента поиск имени (ADL - Argument-Dependent name Lookup).

Поэтому объявите дружественную функцию также после определения класса.

class myClass {
private:
    int i,j;
public:
    myClass();
    virtual ~myClass();
    friend void myFunc();
};
void myFunc();

Сравните данные две демонстрационные программы.

#include <iostream>
class myClass {
private:
    int i,j;
public:
    myClass(){}
    virtual ~myClass(){}
    friend void myFunc() { std::cout << "Hi, I'm friend!" << std::endl; }
};
//void myFunc();
//^^^^^^^^^^^^^^
int main() 
{
    myFunc();
    return 0;
}

и

#include <iostream>
class myClass {
private:
    int i,j;
public:
    myClass(){}
    virtual ~myClass(){}
    friend void myFunc() { std::cout << "Hi, I'm friend!" << std::endl; }
};
void myFunc();
//^^^^^^^^^^^^
int main() 
{
    myFunc();
    return 0;
}

В первом случае возникнет ошибка компиляции, указывающая на то, что имя myFunc не объявлено. Во втором же случае программа успешно скомпилируется и выведет на консоль текст

Hi, I'm friend!

В первом случае когда компилятор встречает имя myFunc, то он ищет его в глобальном пространстве имен и не находит. Поэтому выдает диагностическое сообщение, аналогично показанном вами

'myFunc' was not declared in this scope

Если бы дружественная функция, объявленная в классе, имела аргумент, который имеет тип класса, то компилятор мог бы найти эту функцию, используя зависящий от аргумента поиск имени (ADL). Например,

#include <iostream>
class myClass {
private:
    int i,j;
public:
    myClass() : i( 10 ), j( 20 ){}
    virtual ~myClass(){}
    friend void myFunc( const myClass &c ) 
    { 
        std::cout << "Hi, I'm friend!" << std::endl; 
        std::cout << "You have i = " << c.i << " and j = " << c.j << std::endl;
    }
};
int main() 
{
    myClass c;
    myFunc( c );
    return 0;
}

Данная программа успешно скомпилируется и выведет на консоль

Hi, I'm friend!
You have i = 10 and j = 20

Так как дружественная функция имеет параметр типа const myClass &, то, используя ADL, компилятор будет искать объявление дружественной функции также в классе myClass.

Зависящий от аргумента поиск имени (ADL) можно отключить, если заключить имя функции в скобки. Твк, например, ниже-приведенная программа не будет компилироваться в виду того, что имя функции заключено в круглые скобки, и ADL не будет применен к поиску имени функции.

#include <iostream>
class myClass {
private:
    int i,j;
public:
    myClass() : i( 10 ), j( 20 ){}
    virtual ~myClass(){}
    friend void myFunc( const myClass &c ) 
    { 
        std::cout << "Hi, I'm friend!" << std::endl; 
        std::cout << "You have i = " << c.i << " and j = " << c.j << std::endl;
    }
};

int main() 
{
    myClass c;
    ( myFunc )( c );
    return 0;
}
READ ALSO
Пауза в бесконечном цикле по кнопке

Пауза в бесконечном цикле по кнопке

Консольное приложениеЕсть цикл, в нем по очереди вызываются 3 метода класса

229
emplace_back для int

emplace_back для int

‒ Ты понимаешь, что происходит? ‒ Тебе объяснить? ‒ Объяснить я и сам могу

327
Наследование абстрактного класса в C++

Наследование абстрактного класса в C++

Изучаю тему наследования по практикуму учебника 2010 годаТам есть пример, который я взял для изучения вопроса наследования, где используется...

539
Как в Linux создавать сокеты на С++ с STCP?

Как в Linux создавать сокеты на С++ с STCP?

Делаю всё по книге "Создание сетевых приложений в среде Linux: Руководство разработчика"Не компилируется

372