2012-01-31 13 views
60

Soy un desarrollador JAVA que está tratando de aprender C++, pero realmente no sé cuál es la mejor práctica para declaraciones de funciones estándar.Declaración de función dentro o fuera de la clase

En la clase:

class Clazz 
{ 
public: 
    void Fun1() 
    { 
     //do something 
    } 
} 

o fuera:

class Clazz 
{ 
public: 
    void Fun1(); 
} 

Clazz::Fun1(){ 
    // Do something 
} 

Tengo la sensación de que la segunda puede ser menos legibles ...

+5

¿Quizás un libro para principiantes sobre C++ podría estar en orden? –

+28

@Downvoters ¿por qué? ¿Qué está mal con mi pregunta? – JohnJohnGa

+0

En este momento hay 3 opciones. Su segundo ejemplo podría tener la definición de la función en el archivo de encabezado (pero aún no está en línea), o en un archivo '.cpp' separado. –

Respuesta

13

La primera define su función miembro como inline function, mientras que el segundo no. La definición de la función en este caso reside en el encabezado mismo.

La segunda implementación colocaría la definición de la función en el archivo cpp.

Ambos son semánticamente diferentes y no es solo una cuestión de estilo.

+1

http://www.cplusplus.com/doc/tutorial/classes/ da la misma respuesta: "La única diferencia entre definir una función de miembro de clase completamente dentro de su clase o incluir solo el prototipo y luego su definición, es que en en el primer caso el compilador considerará automáticamente la función como una función miembro en línea, mientras que en el segundo será una función de miembro de clase normal (no en línea), lo que de hecho no supone ninguna diferencia en el comportamiento ". – Buttons840

2

El primero debe colocarse en el archivo de encabezado (donde reside la declaración de la clase). El segundo puede estar en cualquier lugar, ya sea el encabezado o, por lo general, un archivo fuente. En la práctica, puede poner pequeñas funciones en la declaración de la clase (que las declara implícitamente en línea, aunque es el compilador el que finalmente decide si estarán en línea o no). Sin embargo, la mayoría de las funciones tienen una declaración en el encabezado y la implementación en un archivo cpp, como en el segundo ejemplo. Y no, no veo ninguna razón por la cual esto sea menos legible. Sin mencionar que en realidad podría dividir la implementación de un tipo en varios archivos cpp.

37

C++ está orientado a objetos, en el sentido de que admite el paradigma orientado a objetos para el desarrollo de software.

Sin embargo, a diferencia de Java, C++ no lo obliga a agrupar definiciones de funciones en clases: la forma estándar de C++ para declarar una función es simplemente declarar una función, sin ninguna clase.

Si por el contrario se habla de declaración/definición del método a continuación, la forma estándar es poner simplemente la declaración en un archivo de inclusión (normalmente llamado .h o .hpp) y la definición en un archivo de aplicación diferente (normalmente llamado .cpp o .cxx) . Estoy de acuerdo en que esto de hecho es algo molesto y requiere un poco de duplicación, pero así es como se diseñó el lenguaje.

Para experimentos rápidos y proyectos de un solo archivo, cualquier cosa funcionaría ... pero para proyectos más grandes, esta separación es algo que es prácticamente necesario.

Nota: Incluso si conoce Java, C++ es un lenguaje completamente diferente ... y es un lenguaje que no se puede aprender mediante la experimentación. La razón es que es un lenguaje bastante complejo con muchas asimetrías y elecciones aparentemente ilógicas, y lo más importante, cuando cometes un error no hay "ángeles de error de tiempo de ejecución" para salvarte como en Java ... pero en su lugar hay " demonios de comportamiento indefinido ".

La única forma razonable de aprender C++ es leyendo ... no importa cuán inteligente sea usted, no hay manera de que adivine lo que decidió el comité. (En realidad, ser inteligente a veces incluso es un problema porque la respuesta correcta es ilógica y una consecuencia del patrimonio histórico.)

Simplemente elija good book o dos y léalas de principio a fin.

+4

Si alguien viene de Java y pide ayuda en C++, ¿qué le dice si dices "el idioma que conoces está obsesionado con algo"? Él no tiene una comparación con otros idiomas, así que esto no le dice prácticamente nada. Mejor que usar una palabra fuertemente connotada emocionalmente como obsesionada, que no le dice mucho al OP, podrías considerar dejar esta parte. Además, ¿cuál es el contexto de "usar una clase para todo"? En Java, no usas una clase para un método. No usas una clase para una variable. No usas una clase para un archivo ... Entonces, ¿qué es "todo" aquí? Ranting? –

+1

@DanielS: eliminó esa parte porque aparentemente le ofendió (ni idea por qué). Por supuesto que no estoy despotricando acerca de Java porque realmente no uso Java en absoluto, simplemente pensé en ese momento que OOP como Object Obsesed Programming era una broma divertida, mientras que aparentemente no lo es. He sido programador certificado Java 1.1 pero decidí entonces que, a menos que se me forzara por alguna razón, no usaré ese "lenguaje de programación" y hasta ahora logré evitarlo. – 6502

+0

Gracias, creo que se lee mucho mejor ahora. Lo siento si parezco ofendido. Trataré de ser más positivo la próxima vez. –

12

La definición de la función es mejor fuera de la clase. De esa forma, su código puede permanecer seguro si es necesario. El archivo de encabezado solo debe dar declaraciones.

Supongamos que alguien quiere usar su código, puede simplemente darle el archivo .h y el archivo .obj (obtenido después de la compilación) de su clase. Él no necesita el archivo .cpp para usar su código.

De esta forma, su implementación no es visible para nadie más.

8

El método "Dentro de la clase" (I) hace lo mismo que el método "fuera de la clase" (O).

Sin embargo, (I) se puede usar cuando una clase solo se usa en un archivo (dentro de un archivo .cpp). (O) se usa cuando está en un archivo de encabezado. Los archivos cpp siempre se compilan. Los archivos de encabezado se compilan cuando usa #include "header.h".

Si utiliza (I) en un archivo de encabezado, la función (Fun1) se declarará cada vez que incluya #include "header.h". Esto puede llevar a declarar la misma función varias veces. Esto es más difícil de compilar e incluso puede generar errores.

Ejemplo de uso correcto:

Archivo1: "Clazz.h"

//This file sets up the class with a prototype body. 

class Clazz 
{ 
public: 
    void Fun1();//This is a Fun1 Prototype. 
}; 

Archivo2: "Clazz.cpp"

#include "Clazz.h" 
//this file gives Fun1() (prototyped in the header) a body once. 

void Clazz::Fun1() 
{ 
    //Do stuff... 
} 

File3: "UseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz; 
MyClazz.Fun1();//This does Fun1, as prototyped in the header. 

File4: "AlsoUseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz2; 
MyClazz2.Fun1();//This does Fun1, as prototyped in the header. 

File5: "DoNotUseClazzHeader.cpp"

//here we do not include Clazz.h. So this is another scope. 
class Clazz 
{ 
public: 
    void Fun1() 
    { 
     //Do something else... 
    } 
}; 

class MyClazz; //this is a totally different thing. 
MyClazz.Fun1(); //this does something else. 
3

Las funciones miembro pueden ser definidos dentro de la definición de clase o por separado utilizando el operador de resolución de alcance, ::. La definición de una función miembro dentro de la definición de clase declara la función en línea, incluso si no utiliza el especificador en línea. Así que, o se puede definir de la siguiente función de volumen():

class Box 
{ 
    public: 

    double length; 
    double breadth;  
    double height;  

    double getVolume(void) 
    { 
     return length * breadth * height; 
    } 
}; 

Si lo desea, puede definir la función fuera de la misma clase utilizando el operador de resolución de alcance, de la siguiente manera ::

double Box::getVolume(void) 
{ 
    return length * breadth * height; 
} 

En este caso, sólo es importante El punto es que tendrías que usar el nombre de clase justo antes del operador ::. Una función miembro se llamará usando un operador de punto en un objeto donde va a manipular los datos relacionados con ese objeto sólo de la siguiente manera (.):

Box myBox;   

myBox.getVolume(); 

(a partir de: http://www.tutorialspoint.com/cplusplus/cpp_class_member_functions.htm) , ambas formas son legales.

No soy un experto, pero creo que si solo pone una definición de clase en un archivo, entonces en realidad no importa.

pero si aplica algo así como clase interna, o tiene una definición de clase múltiple, la segunda sería difícil de leer y mantener.

+0

¿Puedes traer el contenido relevante de ese enlace al cuerpo de tu publicación y, por lo tanto, a prueba de futuros contra enlaces muertos? Gracias – JustinJDavies

1

Una función que se define dentro de una clase se trata por defecto como una función en línea. una simple razón por la que debe definir su función fuera:

Un constructor de la clase comprueba para funciones virtuales e inicializa un puntero virtual para apuntar a la VTABLE adecuada o la virtual method table, llama al constructor de la clase base, e inicializa las variables de la clase actual, por lo que realmente hace algo de trabajo.

Las funciones en línea se usan cuando las funciones no son tan complicadas y evitan la sobrecarga de la llamada a la función. (La sobrecarga incluye un salto y una bifurcación en el nivel de hardware). Y como se describió anteriormente, el constructor no es tan simple como para considerarse en línea.

Cuestiones relacionadas