Является ли предварительное объявление внутри тела класса другим типом? - PullRequest
3 голосов
/ 24 мая 2019

У меня есть две внутренние структуры внутри окружающего класса, и в одной из структур у меня есть член-указатель на объекты типа другой структуры. И чтобы улучшить читаемость и прояснить, что предварительное объявление предназначено для структуры, которая нуждается в этом, я поместил предварительное объявление в саму внутреннюю структуру. Как то так

class Enclosing{
public:
    struct InnerA{
       struct InnerB; // forward declaration inside InnerA to improve readability  
       InnerB* b; 
       // other members
   };

    struct InnerB{

       // lots of member variables
    };
};

А потом где-то снаружи у меня есть функция

void DoSomething(){
    Enclosing::InnerA a;


    // error incompatible types Enclosing::InnerB* and Enclosing::InnerA::InnerB*
    Enclosing::InnerB* ptr = a.b; 
}

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

Ответы [ 2 ]

7 голосов
/ 24 мая 2019

Да, это считается другой тип.

Объявление помещает имя в область, в которой оно появляется. Каждый класс вводит свою собственную область. Таким образом, в вашем случае у вас есть Enclosing::InnerA::InnerB, что явно отличается от Enclosing::InnerB.

Боюсь, что нет способа объявить имя в другой области, кроме текущей. Вам просто нужно объявить InnerB непосредственно внутри Enclosing до определения InnerA, где оно используется.

4 голосов
/ 24 мая 2019

Ваша предварительная декларация вложена дважды, вы вперед объявляете Enclosing::InnerA::InnerB, но ваше определение для Enclosing::InnerB, поэтому вы на самом деле хотите объявить другой тип.

Вы должны оставаться на том же уровне:

class Enclosing {
  struct InnerB;

  struct InnerA {
    InnerB* ptr;
  };
};

Проблема не в предварительном объявлении как таковом, это как если бы вы делали:

class Enclosing {
  struct InnerA {
    struct InnerB {
      int data;
    };

    InnerB* ptr;
  }; 

  struct InnerB {
    float data;
  };
};

Вы видите, что Enclosing::InnerA::InnerB и Enclosing::InnerB действительно являются разными типами, потому что объявление сохраняет свою локальность, как обычное объявление.

...