Проблема с вложенным объявлением класса/пересылки С++
Можно ли переслать объявить вложенный класс, а затем использовать его как тип для конкретного (не указателя на/ссылку) элемента данных внешнего класса?
т.е.
class Outer;
class Outer::MaybeThisWay // Error: Outer is undefined
{
};
class Outer
{
MaybeThisWay x;
class MaybeThatOtherWay;
MaybeThatOtherWay y; // Error: MaybeThatOtherWay is undefined
};
Ответы
Ответ 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());
}
};