2010-04-08 21 views
32

¿Es posible reenviar-declarar una clase anidada, luego usarla como el tipo de un elemento de datos concreto (no puntero a/referencia) de la clase externa?C++ clase anidada/emisión forward issue issue

I.E.

class Outer; 

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

class Outer 
{ 
MaybeThisWay x; 

class MaybeThatOtherWay; 

MaybeThatOtherWay y; // Error: MaybeThatOtherWay is undefined 
}; 
+0

Su código es el siguiente cadena sin fin de "Outer contiene externa contiene externa contiene exterior ..." – Muxecoid

+0

posible duplicado de [¿Cómo reenviar declarar una clase interna?] (Http://stackoverflow.com/questions/1021793/how-do-i-forward-declare-an-inner-class) –

Respuesta

37

No se puede reenviar-declarar una clase anidada como esa.

Dependiendo de lo que intentes hacer, tal vez puedas usar un espacio de nombres en lugar de una clase en la capa externa. Puede reenviar-declara una clase tan ningún problema:

namespace Outer { 
    struct Inner; 
}; 

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

Si su exterior absolutamente debe ser una clase, y no se puede calzador en un espacio de nombres, entonces usted necesita para exterior para ser una complete el tipo en el contexto donde reenvía declarar interno.

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 
1

No, pero lo que está mal con

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

private: 
    Inner foo; 
}; 

adelante declarando que no tiene sentido aquí, a menos que me falta algo (lo cual es posible ya que su pregunta que falta a una gran cantidad de detalles)

Recuerde, si una clase se declara hacia delante, entonces solo puede declarar referencias o punteros a un objeto del tipo de declaración directa. No puede hacer nada más con eso, incluido el acceso a sus miembros o funciones.

+1

Porque Inner no está adelante declaró que está completamente definido allí. – CashCow

+0

¿Qué pasaría si revierte las secciones aquí? Tal vez algunas funciones en la sección pública usen variables privadas, por lo tanto, necesitan que se declaren, pero Inner también debe ser privado. ¿Cómo permitimos que Inner sea visible en la sección privada ahora? – Sohaib

1

Si una clase ha sido declarada (pero aún no tiene la definición completa), solo puede declarar un puntero, ya que el compilador aún no conoce el tamaño de la clase (ni el nombres de sus campos o métodos).

0

Si declara un atributo de tipo MaybeThatOtherWay, no es una referencia ni un puntero, el compilador debe conocer la definición completa de la clase para determinar el tamaño de la clase externa. Por lo tanto, no puede usar la declaración directa y ese tipo de declaración de campo, ya sea una clase anidada o no.

15

No hay forma de reenviar declarar una clase anidada sin especificar completamente la clase contenedora. Este pequeño truco arregla un poco el problema, sin embargo

class Outer_Inner 
{ 
}; 

class Outer 
{ 
public: 
    typedef Outer_Inner Inner; 
}; 

Esto funciona para mí como en mi convención de nomenclatura Outer_Inner no es un nombre de clase válido, por lo que es obvio que se refiere a una clase anidada.

todavía no puede declarar delante de la clase anidada como esto:

class Outer::Inner; 

Pero por lo menos se puede declarar adelante con:

class Outer_Inner; 

Si no te gusta la forma en Outer_Inner parece que podría adoptar una convención de nomenclatura para las clases anidadas que mejor se adapte a sus gustos. Outer__Inner, Outer_nested_Inner, etc.

+3

No utilice doble guion bajo: los nombres que contienen dos guiones bajos están reservados para la implementación para cualquier uso. Ver http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-ctidentifier/228797#228797 – villintehaspam

+0

¿Es el mismo problema que estoy enfrentando aquí? http://stackoverflow.com/questions/20214740/nested-class-as-a-template-parameter-of-parent-class-in-c –

0

Si solo necesita un tipo como parámetro de función o variable estática, podría hacerlo en el lado del cliente.Por ejemplo, para recibir notificación de eventos del exterior:

Interfaz:

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

Implementación:

#include <outer.hpp> 

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