2016-12-17 2 views
14

Это well-known that one cannot haveчлен типа вы определяете:Почему внутренние термины класса * не могут использовать своих родителей?

class Foo { 
    Foo member; 
}; 

Причина заключается в том, что это бесконечно рекурсивным, бесконечно большой объект. Тем не менее, мы можем иметь статические членов:

class Foo { 
    static Foo member; 
}; 

Мы можем сделать это, потому что Foo действует как пространство имен; экземпляры Foo не содержат .member, поэтому нет бесконечной ссылки. Иными словами, .member относится к классу, а не к экземпляру. То, что я хотел бы сделать, это очень похоже:

class Foo { 
    class Bar { 
     Foo member; 
    }; 
}; 

Еще раз, Foo действует как пространство имен. Экземпляры Foo фактически пусты. Мне нужно было бы создать нестатическое поле Bar Foo::bar;, чтобы начать получать макеты. К сожалению, мои компиляторы не согласен (e.g. GCC):

<source>:3:14: error: field 'member' has incomplete type 'Foo' 
Foo member; 
^~~~~~ 

Для того, что техническая причина это не разрешено?

+4

_acting as namespace_ - Нет, это не что иное, как пространство имен. Пространства имен не хранят данные. 'static Foo' и' Foo member' делает –

+0

, как вы можете сделать со статикой, вы можете со ссылками, и вот что происходит с конструктором копирования. – Raindrop7

+0

Я смущен, почему вы хотели бы сделать это в первую очередь. Я мог бы понять член как 'Foo *', но не предложили бы какие-либо из предложенных нестатических объявлений 'sizeof (Foo)' бесконечно? Я не вижу, как это возможно даже для компиляции –

ответ

21

Короче говоря, было легче запретить это, чем разрешить.

Вот пример, который показывает, что может быть трудно об этом: C++ позволяет сочетать определение вложенного класса с заявлением члена, как это:

class Foo { 
    class Bar { 
     Foo member; 
    } bar; // <<== Here 
}; 

Понятно, почему это определение должно быть запрещено: в отличие от определение класса, которое могло бы быть ОК, определение члена делает невозможным вычисление размера.

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

+2

Вне темы: спасибо (и некоторые upvotes) для очень полезный комментарий к этой пустой печати! – GhostCat

+0

@GhostCat Добро пожаловать! Я видел ваше редактирование, это имеет смысл. Хорошая работа, определяющая эту пустую строку! – dasblinkenlight

19

Нет ничего плохого в том, что вам нужно делать, и вы можете сделать это с помощью другого синтаксиса.

Поскольку компилятор хочет определить размер класса Bar, ему необходимо знать размер класса Foo, но определение Foo еще не завершено (исходный код не был полностью проанализирован компилятором). Определение Foo должно быть завершено до его использования в Bar.

Вместо этого попробуйте переслать объявление в Foo, затем заполните определение Bar после Foo. Таким образом, размер Foo можно определить для использования в Bar.

class Foo { 
    class Bar; 
}; 
class Foo::Bar { 
    Foo member; 
}; 
+1

он не обращается к тому, что спрашивает ОП. – Raindrop7

+7

ОП спросил: «По какой технической причине это запрещено?» Я ясно дал понять, что это связано с определением размера класса. Поскольку определение Foo было неполным, размер Foo не может быть определен, поэтому его нельзя использовать внутри Bar. –

6

Это недопустимо, потому что вы не можете определить класс с элементом с неполным типом, периодом. В конце определения класса класс становится полным, и это возможно только в том случае, если известны размеры всех его членов.

Например, вы получите ту же ошибку, по той же причине, без вложенности классов, как это:

class Foo; 
class Bar { 
    Foo member; 
}; 

Конечно, в вашем примере язык может отложить не завершая определение Foo::Bar до Foo определена, но это будет несовместимо с тем, как определяются классы в целом. У вас было бы странное поведение Foo::Bar неполным в точке исходного кода после его полного определения.

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