Локальные классы в C++
Я читаю концепцию "Локальные классы" в объектно-ориентированном программировании на 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 ответа
Ваш friend
С заявлением все в порядке.
int pqr() {
class abc {
int x;
public:
abc() : x(4) { }
friend int pqr();
};
return abc().x;
}
int main() {
cout << "Return " << pqr() << endl;
}
Редактировать:
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();
}
Кажется, есть неправильное понимание местных классов.
Обычно здесь есть, чтобы помочь вам в функции... и не должны выходить за рамки функции.
Следовательно, функция не может принимать в качестве аргумента свой собственный локальный класс, класс просто не виден снаружи.
Также обратите внимание, что различные компиляторы (к сожалению) не поддерживают эти локальные классы в качестве параметров шаблона (например, gcc 3.4), что фактически препятствует их использованию в качестве предикатов в алгоритмах STL.
Пример использования:
int pqr()
{
class foo
{
friend int pqr();
int x;
foo(): x() {}
};
return foo().x;
}
Я должен признать, хотя, что я не использую это много, учитывая ограниченную область, которую я обычно использую struct
вместо класса, что означает, что мне не нужно беспокоиться о дружбе;)
У меня пока нет решения для друга (даже не знаю, можно ли это сделать), но прочитайте это и это, чтобы узнать больше о местных классах. Это скажет вам, что вы не можете использовать локальные классы вне функции, в которой они определены (как указывает @ In silico в своем ответе).
РЕДАКТИРОВАТЬ Это не представляется возможным, как объясняет эта статья:
Имя функции, впервые введенной в объявлении друга, находится в области видимости первой области некласса, которая содержит включающий класс.
Другими словами, локальные классы могут подружиться с функцией, только если она была объявлена внутри их вмещающей функции.
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 компилятора).