Nota: Las respuestas se dieron en un orden específico , pero dado que muchos usuarios clasifican las respuestas de acuerdo con los votos, en lugar del momento en que se dieron, aquí hay un índice de las respuestas en el orden en que tienen más sentido:
- La sintaxis general de la sobrecarga del operador en C ++
- Las tres reglas básicas de sobrecarga del operador en C ++
- La decisión entre miembro y no miembro
- Operadores comunes para sobrecargar
- Operador de asignación
- Operadores de entrada y salida
- Operador de llamada de función
- Operadores de comparación
- Operadores aritméticos
- Subscripting de matriz
- Operadores para tipos de puntero
- Operadores de conversión
- Sobrecargando nuevo y borrar
(Nota: Esto está destinado a ser una entrada a las preguntas frecuentes de C ++ de Stack Overflow . Si desea criticar la idea de proporcionar una pregunta frecuente en este formulario, entonces la publicación en meta que comenzó todo esto sería el lugar para hacerlo. Respuestas a esa pregunta se monitorea en la sala de chat de C ++ , donde la idea de preguntas frecuentes comenzó en primer lugar, por lo que es muy probable que su respuesta sea leída por aquellos a quienes se les ocurrió la idea).
Respuestas:
Operadores comunes para sobrecargar
La mayor parte del trabajo en operadores de sobrecarga es código de placa de caldera. No es de extrañar, ya que los operadores son simplemente azúcar sintáctica, su trabajo real podría realizarse (y a menudo se reenvía a) funciones simples. Pero es importante que obtenga este código correcto de placa de caldera. Si falla, el código de su operador no se compilará o el código de sus usuarios no se compilará o el código de sus usuarios se comportará sorprendentemente.
Operador de asignación
Hay mucho que decir sobre la asignación. Sin embargo, la mayor parte ya se ha dicho en las famosas preguntas frecuentes de Copiar e intercambiar de GMan, por lo que omitiré la mayor parte aquí, solo enumerando el operador de asignación perfecto para referencia:
Operadores Bitshift (utilizados para Stream I / O)
Los operadores de desplazamiento de bits
<<
y>>
, aunque todavía se usan en la interfaz de hardware para las funciones de manipulación de bits que heredan de C, se han vuelto más frecuentes como operadores de entrada y salida de flujo sobrecargados en la mayoría de las aplicaciones. Para la sobrecarga de la guía como operadores de manipulación de bits, consulte la siguiente sección sobre Operadores aritméticos binarios. Para implementar su propio formato personalizado y lógica de análisis cuando su objeto se utiliza con iostreams, continúe.Los operadores de flujo, entre los operadores sobrecargados más comúnmente, son operadores infix binarios para los cuales la sintaxis no especifica ninguna restricción sobre si deben ser miembros o no miembros. Dado que cambian su argumento izquierdo (alteran el estado de la secuencia), deberían, de acuerdo con las reglas generales, implementarse como miembros del tipo de operando izquierdo. Sin embargo, sus operandos izquierdos son flujos de la biblioteca estándar, y aunque la mayoría de los operadores de salida y entrada de flujo definidos por la biblioteca estándar se definen como miembros de las clases de flujo, cuando implementa operaciones de salida y entrada para sus propios tipos, no puede cambiar los tipos de flujo de la biblioteca estándar. Es por eso que necesita implementar estos operadores para sus propios tipos como funciones que no son miembros. Las formas canónicas de los dos son estas:
Al implementar
operator>>
, configurar manualmente el estado de la secuencia solo es necesario cuando la lectura en sí misma tuvo éxito, pero el resultado no es lo que se esperaría.Operador de llamada de función
El operador de llamada a función, utilizado para crear objetos de función, también conocidos como functores, debe definirse como una función miembro , por lo que siempre tiene el
this
argumento implícito de las funciones miembro. Aparte de esto, se puede sobrecargar para tomar cualquier número de argumentos adicionales, incluido cero.Aquí hay un ejemplo de la sintaxis:
Uso:
En toda la biblioteca estándar de C ++, los objetos de función siempre se copian. Por lo tanto, sus propios objetos de función deberían ser baratos de copiar. Si un objeto de función necesita usar datos que son caros de copiar, es mejor almacenar esos datos en otro lugar y hacer que el objeto de función se refiera a ellos.
Operadores de comparación
Los operadores de comparación de infijo binario deben, de acuerdo con las reglas generales, implementarse como funciones no miembros 1 . La negación del prefijo unario
!
debe (de acuerdo con las mismas reglas) implementarse como una función miembro. (pero generalmente no es una buena idea sobrecargarlo).Los algoritmos
std::sort()
y tipos de la biblioteca estándar (por ejemplostd::map
) siempre esperaránoperator<
estar presentes. Sin embargo, los usuarios de su tipo también esperarán que todos los demás operadores estén presentes , así que si defineoperator<
, asegúrese de seguir la tercera regla fundamental de sobrecarga de operadores y también definir todos los demás operadores de comparación booleanos. La forma canónica de implementarlos es esta:Lo importante a tener en cuenta aquí es que solo dos de estos operadores realmente hacen algo, los otros simplemente envían sus argumentos a cualquiera de estos dos para hacer el trabajo real.
La sintaxis para sobrecargar los operadores booleanos binarios restantes (
||
,&&
) sigue las reglas de los operadores de comparación. Sin embargo, es muy poco probable que encuentre un caso de uso razonable para estos 2 .1 Como con todas las reglas generales, a veces puede haber razones para romper esta también. Si es así, no olvide que el operando de la izquierda de los operadores de comparación binarios, que será para las funciones miembro
*this
, también debe serloconst
. Por lo tanto, un operador de comparación implementado como una función miembro debería tener esta firma:(Tenga
const
en cuenta el al final.)2 Cabe señalar que la versión incorporada de la semántica de acceso directo
||
y su&&
uso. Mientras que los definidos por el usuario (porque son azúcar sintáctica para las llamadas a métodos) no use la semántica de atajos. El usuario esperará que estos operadores tengan semántica de acceso directo, y su código puede depender de ello, por lo tanto, se recomienda NUNCA definirlos.Operadores aritméticos
Operadores aritméticos unarios
Los operadores de incremento y decremento unarios vienen en sabor de prefijo y postfijo. Para distinguir uno del otro, las variantes de postfix toman un argumento int ficticio adicional. Si sobrecarga el incremento o decremento, asegúrese de implementar siempre las versiones de prefijo y postfix. Aquí está la implementación canónica de incremento, decremento sigue las mismas reglas:
Tenga en cuenta que la variante postfix se implementa en términos de prefijo. También tenga en cuenta que postfix hace una copia adicional. 2
La sobrecarga de unario menos y más no es muy común y probablemente sea mejor evitarla. Si es necesario, probablemente deberían sobrecargarse como funciones miembro.
2 También tenga en cuenta que la variante de postfix hace más trabajo y, por lo tanto, es menos eficiente de usar que la variante de prefijo. Esta es una buena razón para preferir generalmente el incremento de prefijo sobre el incremento de postfix. Si bien los compiladores generalmente pueden optimizar el trabajo adicional del incremento de postfix para los tipos incorporados, es posible que no puedan hacer lo mismo para los tipos definidos por el usuario (que podría ser algo tan inocentemente como un iterador de lista). Una vez que se haya acostumbrado a hacerlo
i++
, se hace muy difícil recordar hacerlo++i
cuandoi
no es de tipo incorporado (además, tendría que cambiar el código al cambiar un tipo), por lo que es mejor acostumbrarse siempre usando el incremento de prefijo, a menos que se necesite explícitamente postfix.Operadores aritméticos binarios
Para los operadores aritméticos binarios, no olvide obedecer la tercera sobrecarga del operador de la regla básica: si proporciona
+
, también proporciona+=
, si proporciona-
, no omita-=
, etc. Se dice que Andrew Koenig fue el primero en observar que la asignación compuesta Los operadores se pueden utilizar como base para sus homólogos no compuestos. Es decir, el operador+
se implementa en términos de+=
,-
se implementa en términos de-=
etc.De acuerdo con nuestras reglas generales,
+
y sus compañeros deben ser no miembros, mientras que sus contrapartes de asignación compuesta (+=
etc.), cambiando su argumento izquierdo, deben ser miembros. Aquí está el código ejemplar para+=
y+
; Los otros operadores aritméticos binarios deben implementarse de la misma manera:operator+=
devuelve su resultado por referencia, mientras queoperator+
devuelve una copia de su resultado. Por supuesto, devolver una referencia suele ser más eficiente que devolver una copia, pero en el caso de queoperator+
no haya forma de evitar la copia. Cuando escribea + b
, espera que el resultado sea un nuevo valor, por lo queoperator+
debe devolver un nuevo valor. 3 También tenga en cuenta queoperator+
toma su operando izquierdo por copia en lugar de por referencia constante. La razón de esto es la misma que la razón que da paraoperator=
tomar su argumento por copia.Los operadores de manipulación de bits
~
&
|
^
<<
>>
deben implementarse de la misma manera que los operadores aritméticos. Sin embargo, (excepto por sobrecarga<<
y>>
por salida y entrada) hay muy pocos casos de uso razonable para sobrecargarlos.3 Nuevamente, la lección que se puede extraer de esto es que
a += b
, en general, es más eficiente que,a + b
y debería preferirse, si es posible.Subscripting de matriz
El operador de subíndice de matriz es un operador binario que debe implementarse como miembro de la clase. Se utiliza para tipos similares a contenedores que permiten el acceso a sus elementos de datos mediante una clave. La forma canónica de proporcionar estos es esta:
A menos que no desee que los usuarios de su clase puedan cambiar los elementos de datos devueltos por
operator[]
(en cuyo caso puede omitir la variante no constante), siempre debe proporcionar ambas variantes del operador.Si se sabe que value_type se refiere a un tipo incorporado, la variante const del operador debería devolver mejor una copia en lugar de una referencia const:
Operadores para tipos de puntero
Para definir sus propios iteradores o punteros inteligentes, debe sobrecargar el operador de desreferencia de prefijo unario
*
y el operador de acceso de miembro de puntero infijo binario->
:Tenga en cuenta que estos también necesitarán casi siempre una versión const y una versión sin const. Para el
->
operador, sivalue_type
es declass
(ostruct
ounion
tipo), otrooperator->()
se llama de forma recursiva, hasta que unoperator->()
devuelve un valor de tipo no clase.La dirección unaria del operador nunca debe sobrecargarse.
Para
operator->*()
ver esta pregunta . Raramente se usa y, por lo tanto, rara vez se sobrecarga. De hecho, incluso los iteradores no lo sobrecargan.Continuar a los operadores de conversión
fuente
operator->()
En realidad es extremadamente raro. No es necesario devolver unvalue_type*
- de hecho, puede devolver otro tipo de clase, siempre que ese tipo de clase tenga unoperator->()
, que luego se llamará posteriormente. Esta llamada recursiva deoperator->()
s continúa hasta que sevalue_type*
produce un tipo de retorno. ¡Locura! :)*
en términos de,*=
pero sería incómodo porque una de las primeras operaciones de*=
crear un nuevo objeto, resultado del cálculo. Luego, después del ciclo for-ijk, intercambiaríamos este objeto temporal con*this
. es decir. 1.copy, 2.operator *, 3.swapT* const
retorno de unaconst T&
desreferenciación, que no es el caso. O en otras palabras: un puntero constante no implica un puntero constante. De hecho, no es trivial imitarT const *
, que es la razón de todo el contenidoconst_iterator
de la biblioteca estándar. Conclusión: la firma debería serreference_type operator*() const; pointer_type operator->() const
L <= R
también se puede expresar como en!(R < L)
lugar de!(L > R)
. Podría ahorrar una capa adicional de línea en expresiones difíciles de optimizar (y también es cómo Boost.Operators lo implementa).Las tres reglas básicas de sobrecarga del operador en C ++
Cuando se trata de la sobrecarga del operador en C ++, hay tres reglas básicas que debe seguir . Como con todas esas reglas, de hecho hay excepciones. A veces las personas se han desviado de ellos y el resultado no fue un mal código, pero tales desviaciones positivas son pocas y distantes. Como mínimo, 99 de cada 100 desviaciones que he visto no estaban justificadas. Sin embargo, bien podría haber sido 999 de 1000. Por lo tanto, es mejor que cumpla con las siguientes reglas.
Siempre que el significado de un operador no sea obviamente claro e indiscutible, no debe sobrecargarse. En su lugar, proporcione una función con un nombre bien elegido.
Básicamente, la primera y más importante regla para sobrecargar a los operadores, en esencia, dice: no lo hagas . Puede parecer extraño, porque hay mucho que saber sobre la sobrecarga del operador y muchos artículos, capítulos de libros y otros textos tratan de todo esto. Pero a pesar de esta evidencia aparentemente obvia, solo hay unos pocos casos sorprendentemente donde la sobrecarga del operador es apropiada. La razón es que en realidad es difícil entender la semántica detrás de la aplicación de un operador a menos que el uso del operador en el dominio de la aplicación sea bien conocido e indiscutible. Contrariamente a la creencia popular, este casi nunca es el caso.
Siempre respete la conocida semántica del operador.
C ++ no plantea limitaciones en la semántica de los operadores sobrecargados. Su compilador aceptará felizmente el código que implementa el
+
operadorbinariopara restar de su operando correcto. Sin embargo, los usuarios de dicho operador no se sospecharía la expresióna + b
de restara
a partirb
. Por supuesto, esto supone que la semántica del operador en el dominio de la aplicación es indiscutible.Proporcione siempre todo de un conjunto de operaciones relacionadas.
Los operadores están relacionados entre sí y con otras operaciones. Si su tipo es compatible
a + b
, los usuarios también podrán llamara += b
. Si admite incremento de prefijo++a
, esperarána++
que funcione también. Si pueden verificar sia < b
, seguramente esperarán también poder verificar sia > b
. Si pueden copiar y construir su tipo, esperan que la asignación funcione también.Continúe con la Decisión entre miembro y no miembro .
fuente
boost::spirit
jajaja.+
de la concatenación de cadenas es una violación, pero ahora se ha convertido en una práctica bien establecida, por lo que parece natural. Aunque sí recuerdo una clase de cuerdas caseras que vi en los años 90 que usaba binarios&
para este propósito (refiriéndose a BASIC para la praxis establecida). Pero, sí, ponerlo en la biblioteca estándar básicamente establece esto en piedra. Lo mismo ocurre con el abuso<<
y>>
para IO, por cierto. ¿Por qué el desplazamiento a la izquierda sería la operación de salida obvia? Porque todos lo supimos cuando vimos nuestro primer "¡Hola, mundo!" solicitud. Y por ninguna otra razón.operator==
es que debe ser una relación de equivalencia (IOW, no debe usar NaN sin señalización). Hay muchas relaciones de equivalencia útiles en los contenedores. ¿Qué significa igualdad? "a
igualb
" significa esoa
yb
tiene el mismo valor matemático. El concepto de valor matemático de a (no NaN)float
es claro, pero el valor matemático de un contenedor puede tener muchas definiciones útiles distintas (recursivas de tipo). La definición más fuerte de igualdad es "son los mismos objetos", y es inútil.La sintaxis general de la sobrecarga del operador en C ++
No puede cambiar el significado de los operadores para los tipos integrados en C ++, los operadores solo se pueden sobrecargar para los tipos 1 definidos por el usuario . Es decir, al menos uno de los operandos debe ser de un tipo definido por el usuario. Al igual que con otras funciones sobrecargadas, los operadores pueden sobrecargarse para un determinado conjunto de parámetros solo una vez.
No todos los operadores pueden sobrecargarse en C ++. Entre los operadores que no se pueden sobrecargar están:
.
::
sizeof
typeid
.*
y el único operador ternario en C ++,?:
Entre los operadores que se pueden sobrecargar en C ++ se encuentran estos:
+
-
*
/
%
y+=
-=
*=
/=
%=
(todos los infijos binarios);+
-
(prefijo unario);++
--
(prefijo unario y postfix)&
|
^
<<
>>
y&=
|=
^=
<<=
>>=
(todos los infijos binarios);~
(prefijo unario)==
!=
<
>
<=
>=
||
&&
(todo infijo binario);!
(prefijo unario)new
new[]
delete
delete[]
=
[]
->
->*
,
(todos los infijos binarios);*
&
(todos los prefijos unarios)()
(llamada a función, infijo n-ario)Sin embargo, el hecho de que tú pueda sobrecargar todo esto no significa que deba hacerlo. Consulte las reglas básicas de sobrecarga del operador.
En C ++, los operadores están sobrecargados en forma de funciones con nombres especiales . Al igual que con otras funciones, los operadores sobrecargados generalmente se pueden implementar como una función miembro del tipo de su operando izquierdo o como funciones no miembros . Si es libre de elegir o está obligado a usar cualquiera de ellos depende de varios criterios. 2 Un operador unario
@
3 , aplicado a un objeto x, se invoca comooperator@(x)
o comox.operator@()
. Un operador infijo binario@
, aplicado a los objetosx
yy
, se llama comooperator@(x,y)
o comox.operator@(y)
. 4 4Los operadores que se implementan como funciones que no son miembros a veces son amigos del tipo de su operando.
1 El término "definido por el usuario" puede ser ligeramente engañoso. C ++ hace la distinción entre los tipos integrados y los tipos definidos por el usuario. A los primeros pertenecen, por ejemplo, int, char y double; a este último pertenecen todos los tipos de estructura, clase, unión y enumeración, incluidos los de la biblioteca estándar, aunque no estén, como tales, definidos por los usuarios.
2 Esto está cubierto en una parte posterior de estas preguntas frecuentes.
3 El
@
no es un operador válido en C ++, por eso lo uso como marcador de posición.4 4 El único operador ternario en C ++ no se puede sobrecargar y el único operador n-ary siempre debe implementarse como una función miembro.
Continúe con Las tres reglas básicas de sobrecarga del operador en C ++ .
fuente
~
es un prefijo unario, no un infijo binario..*
falta en la lista de operadores no sobrecargables.:)
operator+()
como una función miembro, pero le dio la firma de una función libre. Ver aquí .La decisión entre miembro y no miembro
Los operadores binarios
=
(asignación),[]
(suscripción de matriz),->
(acceso de miembro), así como el()
operador n-ary (llamada a función), siempre deben implementarse como funciones miembro , porque la sintaxis del lenguaje lo requiere.Otros operadores pueden implementarse como miembros o no miembros. Sin embargo, algunos de ellos generalmente tienen que implementarse como funciones que no son miembros, porque usted no puede modificar su operando izquierdo. Los más destacados son los operadores de entrada y salida
<<
y>>
, cuyos operandos izquierdos son clases de flujo de la biblioteca estándar que no puede cambiar.Para todos los operadores donde tiene que elegir implementarlos como una función miembro o una función no miembro, use las siguientes reglas generales para decidir:
Por supuesto, como con todas las reglas generales, hay excepciones. Si tienes un tipo
y desea sobrecargar los operadores de incremento y decremento, no puede hacer esto como funciones miembro, ya que en C ++, los tipos de enumeración no pueden tener funciones miembro. Por lo tanto, debe sobrecargarlo como una función gratuita. Y
operator<()
para una plantilla de clase anidada dentro de una plantilla de clase es mucho más fácil escribir y leer cuando se hace como una función miembro en línea en la definición de clase. Pero estas son, de hecho, raras excepciones.(Sin embargo, si hace una excepción, no olvide la cuestión de
const
-ness para el operando que, para las funciones miembro, se convierte en elthis
argumento implícito . Si el operador como una función no miembro tomaría su argumento más a la izquierda comoconst
referencia , el mismo operador que una función miembro debe tener unconst
al final para hacer*this
unaconst
referencia).Continuar a operadores comunes para sobrecargar .
fuente
operator+=()
no ser miembro. Tiene que cambiar su operando de la izquierda, por lo que, por definición, tiene que cavar profundamente en sus entrañas. ¿Qué ganarías al no hacerlo miembro?operator +=
elappend
método como con el método. Elappend
método es más completo, porque puede agregar una subcadena del parámetro del índice i al índice n -1:append(string, start, end)
parece lógico que la+=
llamada se agregue constart = 0
yend = string.size
. En ese momento, append podría ser un método de miembro, perooperator +=
no necesita ser un miembro, y convertirlo en un no miembro disminuiría la cantidad de código que se reproduce con las entrañas de String, por lo que es algo bueno ... ^ _ ^ ...Operadores de conversión (también conocidos como conversiones definidas por el usuario)
En C ++ puede crear operadores de conversión, operadores que permiten que el compilador convierta entre sus tipos y otros tipos definidos. Hay dos tipos de operadores de conversión, implícitos y explícitos.
Operadores de conversión implícita (C ++ 98 / C ++ 03 y C ++ 11)
Un operador de conversión implícita permite que el compilador convierta implícitamente (como la conversión entre
int
ylong
) el valor de un tipo definido por el usuario a otro tipo.La siguiente es una clase simple con un operador de conversión implícito:
Los operadores de conversión implícita, como los constructores de un argumento, son conversiones definidas por el usuario. Los compiladores otorgarán una conversión definida por el usuario cuando intenten hacer coincidir una llamada con una función sobrecargada.
Al principio, esto parece muy útil, pero el problema con esto es que la conversión implícita incluso se activa cuando no se espera que lo haga. En el siguiente código,
void f(const char*)
se llamará porquemy_string()
no es un lvalue , por lo que el primero no coincide:Los principiantes se equivocan fácilmente e incluso los programadores experimentados de C ++ a veces se sorprenden porque el compilador elige una sobrecarga que no sospechaban. Estos problemas pueden ser mitigados por operadores de conversión explícitos.
Operadores de conversión explícitos (C ++ 11)
A diferencia de los operadores de conversión implícitos, los operadores de conversión explícitos nunca se activarán cuando no esperes que lo hagan. La siguiente es una clase simple con un operador de conversión explícito:
Observe la
explicit
. Ahora, cuando intenta ejecutar el código inesperado de los operadores de conversión implícitos, obtiene un error del compilador:Para invocar el operador de conversión explícito, debe usar
static_cast
una conversión de estilo C o una conversión de estilo de constructor (es decirT(value)
).Sin embargo, hay una excepción a esto: el compilador puede convertir implícitamente a
bool
. Además, el compilador no puede hacer otra conversión implícita después de que se convierte abool
(un compilador puede hacer 2 conversiones implícitas a la vez, pero solo 1 conversión definida por el usuario como máximo).Debido a que el compilador no lanzará "pasado"
bool
, los operadores de conversión explícitos ahora eliminan la necesidad del lenguaje Safe Bool . Por ejemplo, los punteros inteligentes anteriores a C ++ 11 usaban el lenguaje Safe Bool para evitar conversiones a tipos integrales. En C ++ 11, los punteros inteligentes usan un operador explícito porque el compilador no puede convertir implícitamente a un tipo integral después de convertir explícitamente un tipo a bool.Continuar a Sobrecarga
new
ydelete
.fuente
Sobrecarga
new
ydelete
Nota: Esto solo trata con la sintaxis de sobrecarga
new
ydelete
no con la implementación de dichos operadores sobrecargados. Creo que la semántica de sobrecargarnew
ydelete
merecer sus propias preguntas frecuentes , dentro del tema de la sobrecarga del operador, nunca puedo hacerle justicia.Lo esencial
En C ++, cuando se escribe una nueva expresión como
new T(arg)
dos cosas suceden cuando se evalúa esta expresión: En primer lugaroperator new
se invoca para obtener la memoria prima, y luego el constructor apropiado deT
se invoca para convertir esta memoria en bruto en un objeto válido. Del mismo modo, cuando elimina un objeto, primero se llama a su destructor y luego se devuelve la memoriaoperator delete
.C ++ le permite ajustar ambas operaciones: administración de memoria y construcción / destrucción del objeto en la memoria asignada. Esto último se hace escribiendo constructores y destructores para una clase. La gestión de la memoria de ajuste fino se realiza escribiendo su propio
operator new
yoperator delete
.La primera de las reglas básicas de sobrecarga del operador, no lo haga, se aplica especialmente a la sobrecarga
new
ydelete
. Casi las únicas razones para sobrecargar estos operadores son los problemas de rendimiento y las limitaciones de memoria , y en muchos casos, otras acciones, como los cambios en los algoritmos utilizados, proporcionarán una relación costo / ganancia mucho mayor que intentar modificar la administración de memoria.La biblioteca estándar de C ++ viene con un conjunto de operadores
new
ydelete
operadores predefinidos . Los más importantes son estos:Los dos primeros asignan / desasignan memoria para un objeto, los dos últimos para una matriz de objetos. Si proporciona sus propias versiones de estas, no se sobrecargarán, sino que reemplazarán las de la biblioteca estándar.
Si sobrecarga
operator new
, siempre debe sobrecargar la coincidenciaoperator delete
, incluso si nunca tiene la intención de llamarla. La razón es que, si un constructor lanza durante la evaluación de una nueva expresión, el sistema de tiempo de ejecución devolverá la memoria a laoperator delete
coincidenciaoperator new
que se llamó para asignar la memoria para crear el objeto. Si no proporciona una coincidenciaoperator delete
, se llama al predeterminado, que casi siempre es incorrecto.Si sobrecarga
new
ydelete
, también debería considerar sobrecargar las variantes de la matriz.Colocación
new
C ++ permite que los operadores nuevos y eliminados tomen argumentos adicionales.
La llamada nueva ubicación le permite crear un objeto en una determinada dirección que se pasa a:
La biblioteca estándar viene con las sobrecargas apropiadas de los operadores nuevos y eliminados para esto:
Tenga en cuenta que, en el código de ejemplo para la colocación de nuevos dados anteriormente,
operator delete
nunca se llama, a menos que el constructor de X arroje una excepción.También puede sobrecargar
new
ydelete
con otros argumentos. Al igual que con el argumento adicional para la colocación nueva, estos argumentos también se enumeran entre paréntesis después de la palabra clavenew
. Simplemente por razones históricas, tales variantes a menudo también se llaman colocación nueva, incluso si sus argumentos no son para colocar un objeto en una dirección específica.Específico de clase nuevo y eliminar
Lo más común es que desee ajustar la administración de memoria porque la medición ha demostrado que las instancias de una clase específica, o de un grupo de clases relacionadas, se crean y destruyen a menudo y que la administración de memoria predeterminada del sistema de tiempo de ejecución, ajustada para rendimiento general, trata de manera ineficiente en este caso específico. Para mejorar esto, puede sobrecargar new y delete para una clase específica:
Sobrecargado así, new y delete se comportan como funciones miembro estáticas. Para objetos de
my_class
, elstd::size_t
argumento siempre serásizeof(my_class)
. Sin embargo, estos operadores también son llamados para objetos asignados dinámicamente de clases derivadas , en cuyo caso podría ser mayor que eso.Global nuevo y eliminar
Para sobrecargar el nuevo y eliminar global, simplemente reemplace los operadores predefinidos de la biblioteca estándar con los nuestros. Sin embargo, esto rara vez debe hacerse.
fuente
nothrow
nuevas.¿Por qué no puede
operator<<
funcionarstd::cout
una función miembro para transmitir objetos a un archivo?Digamos que tienes:
Dado eso, no puedes usar:
Como
operator<<
se sobrecarga como una función miembro deFoo
, el LHS del operador debe ser unFoo
objeto. Lo que significa que se le pedirá que use:lo cual es muy no intuitivo.
Si lo define como una función no miembro,
Podrás usar:
lo cual es muy intuitivo
fuente