Pregunta

Este es extracto de codificación directrices de Google c ++.

¿Cómo podemos usar una clase Foo en una cabecera archivo sin acceso a su definición?

  • Se puede declarar miembros de datos de tipo Foo Foo * o y.
  • Se puede declarar (pero no define) funciones con argumentos, y / o valores de retorno, de tipo Foo. (Uno excepción es si un argumento o Foo const Foo y tiene un no explícito, un argumento del constructor, en el cual si necesitamos la definición completa de apoyar la conversión de tipo automático.)
  • Podemos declarar miembros de datos estáticos de tipo Foo. Esto se debe a estático miembros de datos se definen fuera del definición de clase.

Lo siento curiosidad es una excepción en la segunda bala. ¿Por qué esto es tan? ¿Por qué es la definición completa necesaria si queremos apoyar la conversión automática de tipos?

Mi conjetura es que el compilador necesita la definición completa del tipo de destino debido al objeto temporal que se crea en la conversión implícita. ¿Estoy adivinando correctamente? ¿Hay más?

EDIT:

A mi entender, la excepción en la guía se dirige a la situación de esta manera:

class A
{
    public:
        A( int );
};

class B
{
    public:
        B( A const &a );
};

int main()
{
    B b(2);
}

Aquí tenemos sólo una conversión implícita definida por el usuario (de int a A), y llamada a constructor que acepta un const y. Lo único que tiene sentido en esta excepción es apoyar la conversión directa de, por ejemplo, int a A y, a continuación, a través de B constructor que acepta un código de cliente y const, lo que permite utilizar esta cadena de conversión sin necesidad de incluir explícitamente el archivo de cabecera, donde se declara una clase.

¿Fue útil?

Solución

Supongamos que foo.h sabe de declaración Foo única

//foo.h

class Foo;
void f(const Foo &); // It is possible to use the reference.

definición completa es en foo.cpp

// foo.cpp

class CanBeConvertedToFoo;
class Foo
{
   Foo (const CanBeConvertedToFoo & x); // implicit constructor
}

class CanBeConvertedToFoo es convertible implícita a Foo; Pero no se sabe en some.cpp.

// some.cpp

#include "foo.h"
void g(const CanBeConvertedToFoo & x) {
   f(x); // Is it known about implicit conversion ?
}

Otros consejos

El lenguaje C ++ no diferencia entre el código en archivos de cabecera y otro archivo. Ni siquiera se requiere que un encabezado es un archivo. Así puramente técnico la pregunta carece de sentido, pero en la práctica se restringe lo que se hace en la cabecera de los archivos a fin de no correr en conflicto con la Regla Una definición. Sin restringir a sí mismo, los usuarios tienen que tener cuidado para incluir sólo el archivo de cabecera en una unidad de traducción. Con las restricciones apropiadas, el archivo de cabecera puede incluirse libremente en múltiples unidades de traducción.

Un tipo incompleto es uno donde no se conoce el tamaño, donde sizeof no se puede utilizar.

Cuando la definición de clase no se conoce, Foo clase es necesariamente incompleto.

Esto significa que usted no puede hacer las cosas que requiere el tamaño a ser conocido. Y puesto que los medios de incompletitud que los miembros no se conocen (que necesariamente serían conocidos si el tamaño era conocido) no se puede llamar a cualquier miembro general. Excepción:. Que puede llamar al destructor, como en delete pFoo, y el compilador debe aceptar que, pero es un comportamiento indefinido si Foo clase tiene un destructor no trivial

La excepción se indica en las directrices de Google es, sin embargo, carece de sentido.

Editar . Descubrí que la gente en SO gusta más cuando las cosas se explican en detalle, por lo que, añadiendo discusión de ¿Por qué la directriz no tiene sentido

La guía dice que puede "declarar (pero no definir)", pero que "una excepción es si un argumento o Foo Foo const y tiene un no explícita, de un argumento del constructor".

La declaración no tiene nada que ver con los constructores, que se puede afirmar simplemente tratar a cabo:

#include <iostream>

struct Foo;

Foo bar( Foo const& );  // Declaration of function bar, works fine.

struct Foo
{
    int x_;
    Foo( int x ): x_( x ) {}       // Converting constructor.
};

int main()
{
    std::cout << bar( 42 ).x_ << std::endl;
}

Foo bar( Foo const& foo ) { return foo; }

En conclusión, una vez más, a excepción de las directrices de Google no tiene sentido.

Saludos y HTH.,

No sé si la excepción en el segundo punto es cierto. Las conversiones implícitas deben saber sólo cuando se invoca una función, no cuando se declara, por lo que el siguiente funciona a pesar de que C es incompleta mientras f se declara:

#include <iostream>
class C;
void f(C);
struct C { C(int i) { std::cout << "C(" << i << ")" << std::endl; } };
void f(C c) { std::cout << "f(C)" << std::endl; }
int main() { f(2); }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top