Локальные классы в C ++ - PullRequest
4 голосов
/ 13 июля 2010

Я читаю концепцию "Локальные классы" в объектно-ориентированном программировании на C ++. Автор Balagurusamy (http://highered.mcgraw -hill.com / sites / 0070593620 / information_center_view0 / ).

В последней строке сказано: «Функция вложения не может получить доступ к закрытым членам локального класса. Однако этого можно добиться, объявив функцию в качестве друга. "

Теперь мне интересно, как можно сделать подсвеченную часть?

Вот код, который я пробовал, но не повезло,

#include<iostream>
using namespace std;

class abc;

int pqr(abc t)
{
    class abc
    {
        int x;
    public:
        int xyz()
        {
            return x=4;
        }
        friend int pqr(abc);
    };
    t.xyz();
    return t.x;
}

int main()
{
    abc t;
    cout<<"Return "<<pqr(t)<<endl;
}

Я знаю, что код выглядит ошибочно, любая помощь будет полезна.

Ответы [ 4 ]

3 голосов
/ 13 июля 2010

Ваше friend заявление в порядке.

int pqr() {
    class abc {
        int x;
    public:
        abc() : x(4) { }
        friend int pqr();
    };
    return abc().x;
}

int main() {
    cout << "Return " << pqr() << endl;
}

Edit:
IBM предлагает это объяснение проблемы, поднятой в комментариях:

Если вы объявляете друга в локальном классе, а имя друга не определено, компилятор будет искать имя только в самой внутренней охватывающей области некласса. [...] Вы не должны делать это с классами.

void a();

void f() {
  class A {
    // error: friend declaration 'void a()' in local class without prior decl...
    friend void a();
  };
}

friend void a (): Этот оператор не учитывает функцию a (), объявленную в области имен. Поскольку функция a () не была объявлена ​​в области видимости функции f (), компилятор не разрешил бы это утверждение.

Источник: IBM - Область Friend (только C ++)

Итак, вам не повезло. Подсказка Балагурусами работает только для MSVC и подобных компиляторов. Вы можете попробовать передать выполнение статическому методу внутри вашего локального класса в качестве обходного пути:

int pqr() {
    class abc {
        int x;
    public:
        abc() : x(4) { }
        static int pqr() {
            return abc().x;
        }
    };
    return abc::pqr();
}
2 голосов
/ 13 июля 2010

Кажется, есть неправильное понимание местных классов.

Обычно здесь есть люди, которые могут помочь вам в функции ... и НЕ должны выходить за рамки функции.

Следовательно, функция не может принимать в качестве аргумента свой собственный локальный класс, класс просто не виден снаружи.

Также обратите внимание, что различные компиляторы (к сожалению) не поддерживают эти локальные классы в качестве параметров шаблона (например, gcc 3.4), что фактически препятствует их использованию в качестве предикатов в алгоритмах STL.

Пример использования:

int pqr()
{
   class foo
   {
     friend int pqr();
     int x;
     foo(): x() {}
   };

   return foo().x;
}

Я должен признать, что я не использую так много, учитывая ограниченную область, которую я обычно использую struct вместо класса, что означает, что мне не нужно беспокоиться о дружбе;)

1 голос
/ 13 июля 2010

У меня пока нет решения для друга (даже не знаю, можно ли это сделать), но прочитайте this и this , чтобы узнать больше о локальных классах , Это скажет вам, что вы не можете использовать локальные классы вне функции, в которой они определены (как @ In silico указывает в его ответ .)

РЕДАКТИРОВАТЬ Это кажется невозможным, поскольку эта статья объясняет:

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

Другими словами, локальные классы могут подружиться с функцией только в том случае, если она была объявлена ​​внутри их функции.

0 голосов
/ 13 июля 2010

С декларацией friend int pqr(abc); все в порядке. Это не работает, потому что тип abc не был определен до того, как вы использовали его в качестве типа параметра в функции pqr(). Определите его перед функцией:

#include<iostream> 
// By the way, "using namespace std" can cause ambiguities.
// See http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.5
using namespace std;

// Class defined outside the pqr() function.
class abc 
{ 
    int x; 
public: 
    int xyz() 
    { 
        return x=4; 
    } 
    friend int pqr(abc);
}; 

// At this point, the compiler knows what abc is.
int pqr(abc t) 
{ 
    t.xyz(); 
    return t.x; 
} 

int main() 
{ 
    abc t; 
    cout<<"Return "<<pqr(t)<<endl; 
}

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

Однако, если вы знаете, что класс abc будет использоваться только внутри функции pqr(), то можно использовать локальный класс. Но в этом случае вам нужно немного исправить объявление friend.

#include<iostream> 
// By the way, "using namespace std" can cause ambiguities.
// See http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.5
using namespace std;

// pqr() function defined at global scope
int pqr() 
{
    // This class visible only within the pqr() function,
    // because it is a local class.
    class abc
    { 
        int x; 
    public: 
        int xyz() 
        { 
            return x=4; 
        } 
        // Refer to the pqr() function defined at global scope
        friend int ::pqr(); // <-- Note :: operator
    } t;
    t.xyz(); 
    return t.x;
}

int main() 
{ 
    cout<<"Return "<<pqr()<<endl; 
}

Компилируется без предупреждений в Visual C ++ (версия 15.00.30729.01 компилятора).

...