Подтвердить что ты не робот

Проблема с вложенным объявлением класса/пересылки С++

Можно ли переслать объявить вложенный класс, а затем использовать его как тип для конкретного (не указателя на/ссылку) элемента данных внешнего класса?

т.е.

class Outer;

class Outer::MaybeThisWay   // Error: Outer is undefined
{
};

class Outer
{
 MaybeThisWay x;

 class MaybeThatOtherWay;

 MaybeThatOtherWay y;   // Error: MaybeThatOtherWay is undefined
};
4b9b3361

Ответ 1

Вы не можете переслать-объявить вложенный класс.

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

namespace Outer {
   struct Inner; 
};

Outer::Inner* sweets;  // Outer::Inner is incomplete so 
                       // I can only make a pointer to it

Если ваш Outer абсолютно должен быть классом, и вы не можете обучать его в пространстве имен, тогда вам нужно, чтобы Outer был полным типом в контексте, в котором вы отправляете объявление Inner.

class Outer
{
   class Inner;  // Inner forward-declared
};  // Outer is fully-defined now

Outer yes;  // Outer is complete, you can make instances of it
Outer::Inner* fun;  // Inner is incomplete, you can only make 
                    // pointers/references to it

class Outer::Inner 
{
};  // now Inner is fully-defined too

Outer::Inner win;  // Now I can make instances of Inner too

Ответ 2

Невозможно переслать объявление вложенного класса без полного указания содержащего класса. Этот небольшой трюк вроде бы устраняет проблему, хотя

class Outer_Inner
{
};

class Outer
{
public:
   typedef Outer_Inner Inner;
};

Это работает для меня, как в моем соглашении об именах Outer_Inner не является допустимым именем класса, поэтому очевидно, что он относится к вложенному классу.

Вы все еще не можете перенаправить объявление вложенного класса следующим образом:

class Outer::Inner;

Но, по крайней мере, он может быть объявлен с помощью:

class Outer_Inner;

Если вам не нравится, как выглядит Outer_Inner, вы можете принять соглашение об именах для вложенных классов, которые лучше подходят вашим вкусам. Outer__Inner, Outer_nested_Inner и т.д.

Ответ 3

Нет, но что не так с

class Outer {
public:  //or protected or private
    class Inner {
    };

private:
    Inner foo;
};

Вперед декларирование здесь не имеет смысла, если я не пропущу что-то (что возможно, поскольку ваш вопрос не хватает в деталях)

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

Ответ 4

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

Ответ 5

Если вы объявляете атрибут типа MaybeThatOtherWay, а не ссылку или указатель, компилятор должен знать полное определение класса для определения размера внешнего класса. Таким образом, вы не можете использовать форвардное объявление и такое объявление поля, будь то вложенный класс или нет.

Ответ 6

Если вам просто нужен тип как параметр функции или статическая переменная, это может быть сделано на стороне клиента. Например, чтобы получать уведомления о событиях от Outer:

Интерфейс:

class Client {
public:
private:
    static void gotIt(int event);
    class Helper;
};

Реализация:

#include <outer.hpp>

class Client::Helper {
public:
    static void fromOuter(Outer::Inner const& inner) 
    { 
        gotIt(inner.event());
    }
};