2010-11-30 14 views
30

Tengo un fondo C. Me preguntaba por qué la sobrecarga de funciones se agregó a C++. C no tiene sobrecarga de funciones pero C++ sí, ¿cuál era la necesidad?¿Por qué se agregó la sobrecarga de funciones a C++?

¿Qué pasó por la mente del diseñador de idiomas en ese momento?

+18

Uno podría preguntar: ¿por qué, oh, por qué, no se sobrecarga la función en C? Haría mi vida más fácil ... – Raveline

+3

@Raveline: no, no lo haría. – JeremyP

+11

@Raveline: dos palabras; nombre mangling. La pesadilla del desarrollador de objetos compartidos. – falstro

Respuesta

55

Aumenta el mantenimiento. Si tiene un tipo T y llama a una función con él, entonces necesita cambiar T, si la función ha sido sobrecargada para la nueva T, entonces puede recompilarla instantáneamente. En C tendrías que retroceder y buscar en todos los sitios de llamadas y cambiar la función llamada. Tome sqrt(). Si quiere sqrt() un float, entonces tiene que cambiar a sqrtf(). No solo eso, pero el volumen y la complejidad del sistema de tipos de C++ es mucho mayor que en C, y tener que tener nombres de funciones separados para cada posible sobrecarga agotaría rápidamente el conjunto razonable de nombres para funciones que sirven para el mismo propósito. pero tome diferentes argumentos, porque ahora hay muchos más argumentos que tomar.

Por ejemplo, compare las bibliotecas de cadenas C y C++. La biblioteca de cadenas C ofrece un método para agregar a una cadena - strcat(). El std :: string :: append de C++ tiene ocho sobrecargas. ¿Cómo quieres llamarlos? append_a, append_b, etc.? Eso es ridículo: todos cumplen la misma función, solo que de diferentes maneras.

Edit: es realmente vale la pena mencionar que append es un muy mal ejemplo, muchos de los C++ sobrecargas de cuerda son muy redundante. Sin embargo, este es un caso más general que eso y no todos de esas sobrecargas redundantes.

+15

La sobrecarga también tapona algunos agujeros en el sistema tipo C, como 'strchr'. Tener un solo nombre es tan deseable que C ni siquiera * tiene * una versión correcta. Const-safety claramente se considera menos importante que poder usar el mismo nombre ('strchr') independientemente del tipo de argumento. Para mí, este es un buen caso, si te gusta lo suficiente como para ponerlo en tu sistema de tipos, realmente te gustaría sobrecargar aún más. –

+0

@mattdm: sqrtf() fue agregado por una razón. Esa razón no tiene nada que ver con las ventajas de la sobrecarga, que es que es más fácil mantener una llamada sqrt() cuando no tiene que cambiar el sitio de llamadas si cambia un typedef del doble al flotante. Además, ni siquiera sé de qué estás hablando con la sobrecarga del operador, eso ni siquiera es parte de la pregunta. La resolución de sobrecarga de funciones no es una suposición, es un proceso determinista y fácilmente controlado. Si tiene un flotador pero quiere llamar al doble sqrt(), puede lanzar. Es así de simple. – Puppy

+0

Me equivoqué de operador por la función sin una buena razón. Demasiado tarde para editar, así que voy a eliminar y volver a publicar. – mattdm

22

Una buena razón, además de lo que dijo DeadMG, es que si está escribiendo una función de plantilla que p. Ej. llama al sqrt, entonces necesitas un forma genérica de llamar al sqrt - sería muy difícil si intentaras y de alguna forma varieses el nombre a sqrtf, sqrtd, etc., dependiendo del tipo de parámetro de la plantilla. La sobrecarga resuelve este problema, porque entonces sólo hay que escribir sqrt y dejar que la cifra compilador qué sobrecargue se debe utilizar:

template <typename T> 
T sqrt_plus_one(T t) // contrived example 
{ 
    return sqrt(t) + 1; 
} 
+2

Si va a utilizar plantillas, también puede usar la plantilla 'sqrt()' para y luego no necesita sobrecargar. – JeremyP

+3

@JeremyP: las plantillas son una forma de sobrecarga, y la especialización tiene algunas propiedades sorprendentes en el caso de las funciones, en la medida en que la especialización de función de plantilla parcial se consideró * peor que no tenerla *, y por lo tanto no permitida en C++ 03 . Para restringir la sobrecarga de manera que la especialización de la plantilla fuera la única forma de hacerlo, tendrías que resolver esos problemas (no recuerdo los detalles, pero puedes proponer una solución ...) –

+1

@Steve Jessop: En realidad, creo @ JeremyP tiene un punto allí: no creo que el uso de plantillas en todo + alguna forma de especialización sea necesariamente menos poderoso. Me interesaría escuchar las razones concretas por las que este enfoque se consideró horrible. (Aunque es discutible porque el lenguaje ya tenía sobrecarga cuando se consideraban las plantillas, por lo que difícilmente hubieran elegido eliminarlo.) –

0

Utilización de polimorfismo, podemos diseñar una familia de funciones con el mismo nombre de función pero con diferente lista de argumentos . La función realizaría diferentes operaciones dependiendo de la lista de argumentos en la llamada a la función.

+2

Lo que describes no tiene nada que ver con el polimorfismo ... – DevSolar

+2

@DevSolar: eso no es correcto, el polimorfismo no se debe reducir al "polimorfismo de inclusión" (es decir, el método de anulación y subtipificación). La sobrecarga de método/función es también un tipo de polimorfismo, a saber, "polimorfismo ad-hoc". –

+1

@Luc Touraille: estoy corregido. Parece que OOP (http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming) y la programación funcional (http://en.wikipedia.org/wiki/Type_polymorphism) difieren en su definición de "polimorfismo", con el este último tiene un alcance mucho más amplio en el que se aplica el término. Recuperaría el downvote, pero está bloqueado hasta que se edite. :-/ Me disculpo. – DevSolar

3

Trate de encontrar una manera cómoda de construir objetos si no fuera por la sobrecarga de funciones.

std::string foo = "bar"; 
std::vector<std::string> myStringVector; 
myStringVector.push_back(std::string()); 
myStringVector.push_back(std::string("hello")); 
myStringVector.push_back(std::string(foo)); 

Un ejemplo sin sentido, por supuesto, pero ilustra el punto.

Otro punto sería la programación de plantillas. No podría crear plantillas genéricas si tuviera que tener un nombre de función diferente para cada tipo de parámetro.

+0

Este no es un argumento fuerte, porque no hay una razón fundamental por la cual los constructores necesitan tener el mismo nombre que su clase. Es posible imaginar un mundo en el que un constructor sea simplemente un método etiquetado con 'ctor' (un modificador de tipo de método como' inline' que acabo de inventar) y que devuelva una instancia de la clase. En este mundo, la sobrecarga no sería necesaria para construir objetos de diferentes maneras. –

+1

@j_random_hacker: Sí, pero ¿sería * conveniente * llamar a 'ctor new_empty_string()' y 'ctor new_string_from_char_pointer()' y 'ctor new_string_from_string'? – DevSolar

+0

No especialmente :) Pero no es más inconveniente que hacer algo que no esté relacionado con la construcción del objeto (por ejemplo, imprimirlo o agregarle 1) sin sobrecargarlo. (Mi punto es que la construcción de objetos no es un caso que merezca un alegato especial.) –

15

¿Prefiere "seleccionar" uno entre abs/laboratorios/llabs/FABS/fabsf/fabsl O simplemente abs()?

Obviamente, abs().

Así que la sobrecarga de funciones es un alivio para los programadores, la mayoría de las veces, además de otras ventajas.

+0

Su argumento es un argumento para las plantillas/programación genérica, no para la sobrecarga. –

+7

@R, ¿por qué los dos argumentos son mutuamente excluyentes? Diferentes respuestas para los mismos problemas. Es como decir que una minivan no es una respuesta para las familias grandes porque existen SUV. – Chance

+1

@R .... en realidad no. También puede usar el mismo argumento para las plantillas, pero eso no significa que sea exclusivamente para eso. :-) – Nawaz

12

Puede obtener la respuesta directamente de la boca del caballo: The Design and Evolution of C++ por Bjarne Stroustrup dedica un capítulo entero a la sobrecarga, su historia, evolución, concesiones de diseño y decisiones.

no voy a contar la historia aquí, pero voy a mencionar un par de hechos históricos interesantes:

  • operador y la sobrecarga de funciones están estrechamente relacionados;
  • en C++ temprano solía haber una palabra clave especial (overload) que se tenía que usar para declarar un identificador como sobrecargado;
  • la sobrecarga de funciones requiere un enlace de tipo seguro (es decir, manipulación de nombres); cuando se implementó por primera vez, ayudó a descubrir una cantidad sorprendente de errores de tiempo de enlace en el código C y C++ existente (para citar a Stroustrup, era como "ejecutar lint en un programa C por primera vez, algo embarazoso".)
Cuestiones relacionadas