3

Buenas, no entiendo lo siguiente la siguiente linea de código:

Boss* Boss::s_bossInstance = nullptr;

s_bossInstance es una propiedad privada de la clase Boss, entonces,

1.¿Como es posible que pueda accederla fuera de la misma clase?

2.¿Porqué debo tener un tipo de dato de retorno, si es simplemente una propiedad...?(No estoy guardando su contenido, se lo estoy asignando)

3.¿Porque debe estar fuera de la función main si o si?

 class Boss {

    private:
        static Boss* s_bossInstance;

    public:

        static Boss& Get() {
            return *s_bossInstance;
        }

    };

    Boss* Boss::s_bossInstance = nullptr;

El siguiente es otro ejemplo:

struct Entity {

    static int x,y;

    void Print() {
        std::cout << x << "," << y << std::endl;
    }

};

int Entity::x;//Estas lineas de código no entiendo porque nececitan estar
int Entity::y;

int main() {

    Entity e1;
    e1.x = 2;
    e1.y = 3;

    Entity e2;
    e2.x = 5;
    e2.y = 6;



    return 0;
}
MatiEzelQ
  • 1,318
  • 4
  • 19
  • 31

1 Answers1

2

¿Como es posible que pueda accederla fuera de la misma clase?

No puedes acceder a miembros privados de una clase. Pero, puedes crear una función pública para acceder a ellos desde fuera, cosa que estás haciendo aquí:

public:

    static Boss& Get() {
        return *s_bossInstance;
    }

Sin embargo la línea:

Boss* Boss::s_bossInstance = nullptr;

No es acceso al dato s_bossInstance, es una definición del mismo.

¿Por qué debo tener un tipo de dato de retorno, si es simplemente una propiedad?

En C++ todo tiene un tipo, no puede existir una variable sin tipo... desglosemos tu declaración:

//  +---- Tipo
//  |     +--- Ámbito
//  |     |
// vvvv  vvvv                   vvvvvvv <--- Inicializador.
   Boss* Boss::s_bossInstance = nullptr;
 //    ^       ^^^^^^^^^^^^^^ <--- nombre
 //    |
 //    +---- Puntero

Tu declaración dice "Define un objeto de tipo puntero a Boss con el nombre s_bossInstance dentro del ámbito Boss y asígnale el valor nullptr", si no le indicaras el tipo no compilaría.

¿Porque debe estar fuera de la función main si o si?

Supongo que quieres saber por qué la definición de un miembro estático de una clase debe estar fuera de la clase (ninguna relación con la función main).

Hemos de distinguir tres conceptos separados al crear elementos en C++, estos conceptos son:

  • Declaración: Indica al compilador que algo existe sin entrar en detalles de cómo es.
  • Definición: Describe algo al compilador con todo detalle posible, si no se declaró anteriormente la definición se considera ambas cosas.
  • Enlazado: El proceso realizado por el enlazador que consiste en emparejar cada declaración con su definición.

Esta separación entre declaración y definición permite a C++ separar el código en archivos de cabecera y archivos de código u optimizar la compilación mediante pre-declaraciones.

También fuerza a tomar ciertas decisiones como:

  • Definir todo aquello que sea usado: si usas algo declarado sin definirlo, obtendrás un error de enlazado habitualmente escrito como "Símbolo Externo sin resolver".
  • Definir una sóla vez (regla de definición única): si algo es definido más de una vez, aunque todas las definiciones sean iguales, el enlazador no sabrá que definición usar y fallará también al enlazar.

En el caso de un miembro estático de una clase, su declaración está englobada en el ámbito del objeto al que pertenece pero carece de definición; es decir: el compilador sabe que existe pero no sabe cómo es... para decirle al compilador cómo es ese objeto estático debes definirlo y ésto se hace fuera del objeto que lo engloba:

class Boss {
    // declaracion: s_bossInstance existe y es de tipo Boss*.
    static Boss* s_bossInstance; 
};

// definicion: s_bossInstance existe, es de tipo Boss* y su valor es nullptr.
Boss* Boss::s_bossInstance = nullptr; 

A grandes rasgos, un miembro estático de un objeto no está ligado a ninguna instancia del objeto por lo que su declaración está en el objeto en si pero su definición debe ser externa ya que en caso contrario, si el objeto Boss (que incluiría la definición de s_bossInstance) es declarado varias veces (por ejemplo: si está en una cabecera y ésta cabecera se incluye en varios archivos) se daría una ambigüedad al intentar enlazar.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
  • En el (1), por lo que entiendo, si estoy accediendo a la propiedad `s_bossInstance` fuera de la clase, en esta linea de código: `Boss* Boss::s_bossInstance = nullptr;`. Esa línea esta fuera de el método `main` y fuera de la clase a la vez. – MatiEzelQ Oct 09 '17 at 15:56
  • 1
    Estás confundiendo un acceso con la definición de la variable estática. – PaperBirdMaster Oct 09 '17 at 15:58
  • En el (2), estoy asignandole a `Boss::s_bossInstance` un valor, por eso no entiendo la nececidad de declarar un tipo de retorno – MatiEzelQ Oct 09 '17 at 15:58
  • Estás asignando un valor porque es una definición, requiere un tipo porque es una definición. El tipo no es de retorno, es el tipo asignado al dato definido. – PaperBirdMaster Oct 09 '17 at 15:59
  • Y porque es necesario hacer la definición? Ya lo vi en otra parte y no entiendo :( Es simplemente un valor default para la propiedad? – MatiEzelQ Oct 09 '17 at 16:00
  • 1
    Ampliaré la respuesta para explicarlo, pero es bastante técnico y tardaré un buen rato. – PaperBirdMaster Oct 09 '17 at 16:04
  • Mil gracias!!!! – MatiEzelQ Oct 09 '17 at 16:06
  • Acá encontre una gran explicación: http://www.learncpp.com/cpp-tutorial/811-static-member-variables/ – MatiEzelQ Oct 09 '17 at 18:17