2013-11-28 3 views
0

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

Идея заключается в том, чтобы иметь следующую закономерность:

void SomeClass::someMethod() 
{ 
    struct A 
    { 
     B * b; 
     void foo() { if(b) b->bar(); }; 
    }; 
    struct B 
    { 
     A * a; 
     void bar() { if(a) a->foo(); } 
    }; 
} 

Но это не компилируется, потому что A потребности B. Вперед декларирование B помогает скомпилировать строку B * b;, но для этого метода A::foo() требуется полное объявление B, и компилятор жалуется.

Я вижу два обходные пути:

  1. объявления и определения классов в SomeClass.cpp до SomeClass::someMethod(). Я чувствую, что это не изящно, поскольку не только классы не являются локальными для SomeClass::someMethod(), но даже не локальны для SomeClass.

  2. Объявление классов в SomeClass.h, вложенных в SomeClass, и определение их в SomeClass.cpp. Мне не нравится это решение либо потому, что не только классы не являются локальными для SomeClass::someMethod(), но он загрязняет SomeClass.h без уважительной причины, кроме ограничения языка.

Отсюда два вопроса: можно ли вообще иметь классы, локальные для SomeClass::someMethod()? Если нет, вы видите более элегантные обходные пути?

+0

Почему вам это нужно локально внутри метода? вы можете объявить/определить их только в файле .cpp и не загрязнять файл .h. –

+0

@BryanChen: на самом деле это не значит, что я * нуждаюсь в этом, это просто более элегантно, если я могу: если класс детали реализации для метода, а затем определение его внутри метода - это место, где оно принадлежит. Просто хорошая инкапсуляция ООП. – Boris

+0

@Boris Его инкапсуляция, но не OOP. – woolstar

ответ

0

Поскольку ответ, кажется: «это не возможно, чтобы иметь чистые взаимозависимых локальные классы», оказывается, что обходной путь, который мне больше всего нравится, - это переместить логику вне самих структур. Как было предложено remyabel в комментариях к этому вопросу, это можно сделать, создав третий класс, но мой любимый подход - создать взаиморекурсивные лямбда-функции, поскольку он позволяет захватывать переменные (следовательно, делает мою жизнь проще в моем реальном случае Применение). Так он выглядит:

#include <functional> 
#include <iostream> 

int main() 
{ 
    struct B; 
    struct A { B * b; }; 
    struct B { A * a; }; 

    std::function< void(A *) > foo; 
    std::function< void(B *) > bar; 

    foo = [&] (A * a) 
    { 
     std::cout << "calling foo" << std::endl; 
     if(a->b) { bar(a->b); } 
    }; 
    bar = [&] (B * b) 
    { 
     std::cout << "calling bar" << std::endl; 
     if(b->a) { foo(b->a); } 
    }; 

    A a = {0}; 
    B b = {&a}; 
    foo(&a); 
    bar(&b); 

    return 0; 
} 

Это компилирует и печатает:

calling foo 
calling bar 
calling foo 

Обратите внимание, что тип лямбды должны быть указаны вручную, так как определение типа не очень хорошо работает с рекурсивными лямбды.

1

Реализация виртуального A, B для использования, то реальное А.

struct virtA 
{ 
    virtual void foo() = 0 ; 
} ; 
struct B 
{ 
    virtA * a ; 
    void bar() { if (a) { a->foo() ; } } 
} ; 
struct A : public virtA 
{ 
    B * b ; 
    void bar() { if (b) { b-> bar() ; } } 
} ; 
+0

А, ладно, нам нужно немного подойти к ужасу. – woolstar

Смежные вопросы