2010-12-13 8 views
11
class Temp { 
    public : 
     Temp(X& x): x_(x) {} 
     Temp(X& x, Y& y) : x_(x), y_(y) {} 
     ... 
    private: 
     X& x_; 
     Y& y_; 
} 

yo conseguimos el error debido a que en caso de Temp(X& x): x_(x) la referencia y_ no se ha inicializado. ¿Cuál es la práctica común para escribir una clase así correctamente?referencias miembros iniciar correctamente

Respuesta

10

voy a sugerir otro enfoque, a pesar de que no puede ser lo que usted está buscando.

No utiliza variables de referencia (punteros de memoria en su lugar), sino que también no utiliza impulso, sino que le permitirá mantener las dos constructores sin destinar más recursos de memoria.

#include <iostream> 

class Temp 
{ 
    public : 
     Temp(int& x): x_(&x), y_(NULL) {} 
     Temp(int& x, int& y) : x_(&x), y_(&y) {} 
     void print() { std::cout << "*x_: " << *x_ << std::endl; } 

    private: 
     int* x_; 
     int* y_; 
}; 

int main() 
{ 
    int x = 5; 
    Temp tmp(x); 

    tmp.print(); 

    return 0; 
} 
+1

Considere' int * const x_; 'y' int * const y_; 'para conservar el comportamiento existente (ya que las referencias no pueden ser reintegrado). –

2

La práctica común, en honor a la verdad, es no utilizar referencias como miembros de datos de una estructura o clase.

¿Por qué crees que quieres hacer esto? Una referencia es, conceptualmente, otro nombre para una cosa ya existente. Los objetos son, bueno, objetos. Deberías poder crearlos de una tela entera. A veces tendrán punteros (o instancias de alguna clase de puntero inteligente) a otras cosas que ya existen, pero al menos el puntero en sí es información real.

+4

Una vista estrecha, y no estoy de acuerdo. A veces, un miembro de referencia es la mejor manera de capturar algo. Por ejemplo, las clases efímeras que se utilizan para analizar o enumerar un blob de datos pueden tener una referencia a ese blob de datos. –

+2

-1: no, la referencia como miembro de una clase es una restricción sobre la preexistencia del objeto al que se hace referencia. Ya lo usé y lo he visto usado. –

10

No se puede tener miembros de referencia que no se inicializan! Si este es el caso, considere envolver la referencia en boost::optional, luego puede construir opcionalmente la referencia.

EDIT: aquí es el enfoque boost::optional ...

class Temp { 
    public : 
     Temp(X& x): x_(x) {} 
     Temp(X& x, Y& y) : x_(x), y_(y) {} 
     ... 
    private: 
     X& x_; 
     boost::optional<Y&> y_; // by default this is constructed with none_t 
} 
+0

'boost :: optional' funciona con tipos de referencia para el tipo de plantilla? Ahora quiero buscar cómo consiguieron que funcione ... –

+0

@Karl, yip: es una de las mejores características de 'boost :: optional' IMHO ... – Nim

1

tiene una referenciaa Y_! Las referencias deben tener las iniciales y su primer constructor no. Si no puede vincularse a y cuando se crea la clase, probablemente debería usar un puntero.

0

Elimina el primer constructor o elimina la segunda referencia. Si tiene una referencia, debe inicializarla de inmediato. Si debe proporcionar un constructor que inicialice de forma predeterminada el miembro Y, haga que el miembro Y sea un puntero o una variable automática.

7

Tener un miembro de datos que es una referencia es un contrato FUERTE: Esto significa que usted no puede tener un nullptr o un objeto definido, su clase necesita este objeto, el objeto tiene que existir.

Como consecuencia, su primer constructor viola este fuerte contrato, y en consecuencia no puede compilar.

Como karlphillip sugiere: se debe utilizar punteros, ya que no quiere respetar un contrato de tal manera que asegura que siempre se define _y.

Es válido tener referencias como miembro, si su doesnt clase tiene sentido sin la preexistencia de los objetos referenciados.

+0

Sin duda es válido, pero mi posición es que este tipo de condición previa de "esta otra cosa debe existir" es inusual, y ** podría ** indicar un defecto de diseño (¿no podemos simplemente adquirir nuestro propio recurso? ¿De verdad queremos? para usar OO para este particular bit de funcionalidad? etc.) Los miembros de datos de referencia también pueden ser difíciles de manejar: además del problema del OP, considere la tarea de escribir un constructor de copia, o un operador de asignación. Se necesita mucho más pensamiento para razonar a través de la semántica adecuada y más esfuerzo para satisfacer al compilador también. Pero +1 para describir el contrato. –

+0

@Karl, su derecho a veces puede ser un defecto de diseño. Eliminaré el -1 que te di ;-) –

+0

Hay muy pocas cosas en la programación sobre las que soy completamente inflexible. Pero cuando creo que algo a menudo no es la idea correcta, me gusta expresar mis objeciones con firmeza, porque me temo que, de lo contrario, las personas encontrarán demasiado fácil justificar un mal diseño para su situación particular. "Oh, pero yo soy especial"; no; casos especiales no son lo suficientemente especiales. ;) –

Cuestiones relacionadas