Nota: As respostas foram dadas em uma ordem específica , mas como muitos usuários classificam as respostas de acordo com os votos, e não com o tempo que receberam, aqui está um índice das respostas na ordem em que fazem mais sentido:
- A sintaxe geral da sobrecarga de operadores em C ++
- As três regras básicas de sobrecarga de operadores em C ++
- A decisão entre membro e não membro
- Operadores comuns a sobrecarregar
- Operador de atribuição
- Operadores de entrada e saída
- Operador de chamada de função
- Operadores de comparação
- Operadores aritméticos
- Subscrição de Matrizes
- Operadores para tipos semelhantes a ponteiros
- Operadores de conversão
- Sobrecarregando novos e excluídos
(Observação: isso deve ser uma entrada para as Perguntas frequentes sobre C ++ do Stack Overflow . Se você quiser criticar a idéia de fornecer uma FAQ neste formulário, a postagem na meta que iniciou tudo isso seria o lugar para isso. essa pergunta é monitorada na sala de chat do C ++ , onde a idéia de FAQ começou em primeiro lugar; portanto, é muito provável que sua resposta seja lida pelos que a tiveram.)
Respostas:
Operadores comuns a sobrecarregar
A maior parte do trabalho em sobrecarregar os operadores é do código da placa da caldeira. Isso não é de admirar, já que os operadores são apenas açúcar sintático, seu trabalho real poderia ser feito por (e muitas vezes é encaminhado para) funções simples. Mas é importante que você consiga esse código de caldeira correto. Se você falhar, o código do seu operador não será compilado ou o código dos seus usuários não será compilado ou o código dos seus usuários se comportará de maneira surpreendente.
Operador de atribuição
Há muito a ser dito sobre a atribuição. No entanto, a maior parte já foi mencionada nas famosas Perguntas frequentes sobre copiar e trocar do GMan , por isso vou pular a maioria aqui, listando apenas o operador de atribuição perfeito para referência:
Operadores Bitshift (usados para E / S de fluxo)
Os operadores de deslocamento de bits
<<
e>>
, embora ainda sejam usados na interface de hardware para as funções de manipulação de bits que eles herdam de C, tornaram-se mais prevalentes como operadores de entrada e saída de fluxo sobrecarregados na maioria dos aplicativos. Para obter sobrecarga de orientação como operadores de manipulação de bits, consulte a seção abaixo em Operadores aritméticos binários. Para implementar seu próprio formato customizado e lógica de análise quando seu objeto é usado com iostreams, continue.Os operadores de fluxo, entre os operadores mais sobrecarregados, são operadores de infixo binário para os quais a sintaxe não especifica nenhuma restrição sobre se devem ser membros ou não membros. Como eles alteram o argumento esquerdo (alteram o estado do fluxo), devem, de acordo com as regras gerais, ser implementados como membros do tipo do operando esquerdo. No entanto, seus operandos esquerdos são fluxos da biblioteca padrão e, enquanto a maioria dos operadores de saída e entrada de fluxo definidos pela biblioteca padrão são realmente definidos como membros das classes de fluxo, quando você implementa operações de saída e entrada para seus próprios tipos, você não pode alterar os tipos de fluxo da biblioteca padrão. É por isso que você precisa implementar esses operadores para seus próprios tipos como funções não membros. As formas canônicas das duas são estas:
Ao implementar
operator>>
, a configuração manual do estado do fluxo só é necessária quando a leitura em si é bem-sucedida, mas o resultado não é o que seria esperado.Operador de chamada de função
O operador de chamada de função, usado para criar objetos de função, também conhecidos como functores, deve ser definido como uma função membro , para que ele sempre tenha o
this
argumento implícito das funções membro. Fora isso, pode ser sobrecarregado para receber qualquer número de argumentos adicionais, incluindo zero.Aqui está um exemplo da sintaxe:
Uso:
Em toda a biblioteca padrão C ++, os objetos de função são sempre copiados. Portanto, seus próprios objetos de função devem ser baratos para copiar. Se um objeto de função precisar absolutamente usar dados caros de copiar, é melhor armazenar esses dados em outro local e fazer com que o objeto de função se refira a ele.
Operadores de comparação
Os operadores binários de comparação de infixos devem, de acordo com as regras práticas, ser implementados como funções não membros 1 . A negação de prefixo unário
!
deve (de acordo com as mesmas regras) ser implementada como uma função de membro. (mas geralmente não é uma boa idéia sobrecarregá-lo.)Os algoritmos da biblioteca padrão (por exemplo
std::sort()
) e tipos (por exemplostd::map
) sempre esperamoperator<
estar presentes. No entanto, os usuários do seu tipo também esperam que todos os outros operadores estejam presentes ; portanto, se você definiroperator<
, siga a terceira regra fundamental de sobrecarga de operadores e também defina todos os outros operadores de comparação booleana. A maneira canônica de implementá-los é esta:O importante a ser observado aqui é que apenas dois desses operadores realmente fazem alguma coisa, os outros estão apenas encaminhando seus argumentos para esses dois para fazer o trabalho real.
A sintaxe para sobrecarregar os demais operadores booleanos binários (
||
,&&
) segue as regras dos operadores de comparação. No entanto, é muito improvável que você encontre um caso de uso razoável para esses 2 .1 Como em todas as regras práticas, às vezes também pode haver razões para quebrar essa. Nesse caso, não esqueça que o operando esquerdo dos operadores de comparação binária, que será para funções-membro
*this
, também precisa serconst
. Portanto, um operador de comparação implementado como uma função membro teria que ter esta assinatura:(Observe
const
no final.)2 Note-se que o built-in versão do
||
e&&
semântica uso de atalho. Enquanto os definidos pelo usuário (por serem açúcar sintático para chamadas de método) não usam semântica de atalho. O usuário espera que esses operadores tenham semântica de atalho, e seu código pode depender disso. Portanto, é altamente recomendável NUNCA defini-los.Operadores aritméticos
Operadores aritméticos unários
Os operadores de incremento e decréscimo unários são fornecidos no formato prefixo e postfix. Para diferenciar uma das outras, as variantes do postfix usam um argumento int adicional adicional. Se você sobrecarregar o incremento ou o decremento, sempre implemente as versões de prefixo e postfix. Aqui está a implementação canônica do incremento, o decremento segue as mesmas regras:
Observe que a variante postfix é implementada em termos de prefixo. Observe também que o postfix faz uma cópia extra. 2
Sobrecarregar menos e mais unário não é muito comum e provavelmente é melhor evitar. Se necessário, eles provavelmente devem estar sobrecarregados como funções de membro.
2 Observe também que a variante postfix funciona mais e, portanto, é menos eficiente do que a variante prefixo. Esse é um bom motivo para preferir geralmente o incremento do prefixo ao incremento do pós-fixado. Embora os compiladores geralmente possam otimizar o trabalho adicional de incremento do postfix para tipos internos, eles podem não ser capazes de fazer o mesmo para tipos definidos pelo usuário (que podem parecer tão inocentemente quanto um iterador de lista). Depois que você se acostuma
i++
, é muito difícil lembrar de fazer++i
quandoi
não é do tipo interno (além disso, você precisa alterar o código ao alterar um tipo); portanto, é melhor criar o hábito de sempre usando incremento de prefixo, a menos que o postfix seja explicitamente necessário.Operadores aritméticos binários
Para os operadores aritméticos binários, não se esqueça de obedecer à terceira sobrecarga de operadores de regras básicas: se você fornecer
+
, também fornecer+=
, se fornecer-
, não omitir-=
etc. etc. Diz-se que Andrew Koenig foi o primeiro a observar que a atribuição composta operadores podem ser usados como base para suas contrapartes não compostas. Ou seja, o operador+
é implementado em termos de+=
,-
é implementado em termos de-=
etc.De acordo com nossas regras práticas,
+
e seus companheiros devem ser não membros, enquanto seus colegas de designação composta (+=
etc.), alterando seu argumento à esquerda, devem ser membros. Aqui está o código exemplar para+=
e+
; os outros operadores aritméticos binários devem ser implementados da mesma maneira:operator+=
retorna o resultado por referência, enquantooperator+
retorna uma cópia do resultado. Obviamente, retornar uma referência geralmente é mais eficiente do que retornar uma cópia, mas, no caso deoperator+
, não há como contornar a cópia. Quando você escrevea + b
, espera que o resultado seja um novo valor, e é por issooperator+
que deve retornar um novo valor. 3 Observe também queoperator+
pega o operando esquerdo por cópia, e não por referência const. A razão para isso é a mesma que a razão paraoperator=
o argumento por cópia.Os operadores de manipulação de bits
~
&
|
^
<<
>>
devem ser implementados da mesma maneira que os operadores aritméticos. No entanto, (exceto para sobrecarga<<
e>>
saída e entrada), existem muito poucos casos de uso razoáveis para sobrecarregá-los.3 Novamente, a lição a ser tirada disso é que
a += b
, em geral, é mais eficientea + b
e deve ser preferível, se possível.Subscrição de Matrizes
O operador de subscrito da matriz é um operador binário que deve ser implementado como um membro da classe. É usado para tipos semelhantes a contêineres que permitem acesso aos seus elementos de dados por uma chave. A forma canônica de fornecê-los é a seguinte:
A menos que você não queira que os usuários da sua classe possam alterar os elementos de dados retornados por
operator[]
(nesse caso, você pode omitir a variante não-const), sempre forneça as duas variantes do operador.Se value_type é conhecido por se referir a um tipo interno, a variante const do operador deve retornar melhor uma cópia em vez de uma referência const:
Operadores para tipos semelhantes a ponteiros
Para definir seus próprios iteradores ou ponteiros inteligentes, é necessário sobrecarregar o operador de desreferência de prefixo unário
*
e o operador de acesso ao membro do ponteiro de infixo binário->
:Observe que eles também quase sempre precisam de uma versão const e uma não-const. Para o
->
operador, sevalue_type
for do tipoclass
(oustruct
ouunion
), outrooperator->()
é chamado recursivamente, até que umoperator->()
retorne um valor do tipo não pertencente à classe.O endereço unário do operador nunca deve ser sobrecarregado.
Para
operator->*()
ver esta pergunta . É raramente usado e, portanto, raramente sobrecarregado. De fato, mesmo os iteradores não sobrecarregam.Continue para Operadores de conversão
fonte
operator->()
é realmente extremamente estranho. Não é necessário retornar umvalue_type*
- na verdade, ele pode retornar outro tipo de classe, desde que o tipo de classe possua umoperator->()
, que será chamado posteriormente. Essa chamada recursiva deoperator->()
s continua até que umvalue_type*
tipo de retorno ocorra. Loucura! :)*
em termos de,*=
mas seria estranho, porque uma das primeiras operações de*=
criaria um novo objeto, resultado da computação. Depois, após o loop for-ijk, trocaríamos esse objeto temporário por*this
. ie 1.copy, 2.operator *, 3.swapT* const
retorno de umaconst T&
dreferenciação, o que não é o caso. Ou, em outras palavras: um ponteiro const não implica um ponteiro const. De fato, não é trivial imitarT const *
- que é a razão de todo oconst_iterator
material na biblioteca padrão. Conclusão: a assinatura deve serreference_type operator*() const; pointer_type operator->() const
L <= R
também pode ser expresso como em!(R < L)
vez de!(L > R)
. Pode salvar uma camada extra de embutimento em expressões difíceis de otimizar (e também é como o Boost.Operators o implementa).As três regras básicas de sobrecarga de operadores em C ++
Quando se trata de sobrecarga de operadores em C ++, existem três regras básicas que você deve seguir . Como com todas essas regras, existem de fato exceções. Às vezes, as pessoas se desviaram delas e o resultado não foi um código ruim, mas esses desvios positivos são poucos e distantes entre si. No mínimo, 99 dos 100 desvios que eu vi foram injustificados. No entanto, pode ter sido 999 em 1000. Portanto, é melhor seguir as regras a seguir.
Sempre que o significado de um operador não for obviamente claro e indiscutível, ele não deverá ser sobrecarregado. Em vez disso, forneça uma função com um nome bem escolhido.
Basicamente, a primeira e principal regra para sobrecarregar os operadores, no fundo, diz: Não faça isso . Isso pode parecer estranho, porque há muito a ser conhecido sobre a sobrecarga do operador e, portanto, muitos artigos, capítulos de livros e outros textos lidam com tudo isso. Mas, apesar dessa evidência aparentemente óbvia, há apenas surpreendentemente poucos casos em que a sobrecarga do operador é apropriada. O motivo é que, na verdade, é difícil entender a semântica por trás da aplicação de um operador, a menos que o uso do operador no domínio do aplicativo seja bem conhecido e indiscutível. Ao contrário da crença popular, esse quase nunca é o caso.
Sempre mantenha a semântica conhecida do operador.
C ++ não apresenta limitações na semântica de operadores sobrecarregados. Seu compilador aceitará com prazer o código que implementa o
+
operadorbináriopara subtrair do operando direito. No entanto, os utilizadores de um operador como nunca suspeitaria a expressãoa + b
para subtraira
a partirb
. Obviamente, isso supõe que a semântica do operador no domínio do aplicativo seja indiscutível.Sempre forneça tudo de um conjunto de operações relacionadas.
Os operadores estão relacionados entre si e com outras operações. Se o seu tipo suportar
a + b
, os usuários esperam poder ligara += b
também. Se ele suportar incremento de prefixo++a
, eles esperama++
que funcione também. Se eles puderem verificar sea < b
, certamente esperarão também poder verificar sea > b
. Se eles podem copiar e construir seu tipo, esperam que a atribuição funcione também.Continue em A decisão entre membro e não membro .
fonte
boost::spirit
lol.+
da concatenação de cordas é uma violação, mas agora se tornou uma práxis bem estabelecida, de modo que parece natural. Embora eu me lembre de uma classe de cordas caseira que vi nos anos 90 que usava o binário&
para esse fim (referindo-se ao BASIC para a prática estabelecida). Mas, sim, colocá-lo na lib std basicamente define isso em pedra. O mesmo vale para abusar<<
e>>
para IO, BTW. Por que a mudança à esquerda seria a operação de saída óbvia? Porque todos nós aprendemos sobre isso quando vimos nosso primeiro "Olá, mundo!" inscrição. E por nenhuma outra razão.operator==
é que deve haver uma relação de equivalência (IOW, você não deve usar NaN sem sinalização). Existem muitas relações úteis de equivalência em contêineres. O que significa igualdade? "a
igualb
" significa issoa
eb
tem o mesmo valor matemático. O conceito de valor matemático de a (não NaN)float
é claro, mas o valor matemático de um contêiner pode ter muitas definições úteis distintas (tipo recursiva). A definição mais forte de igualdade é "eles são os mesmos objetos" e é inútil.A sintaxe geral da sobrecarga de operadores em C ++
Você não pode alterar o significado de operadores para tipos internos em C ++; os operadores podem ser sobrecarregados apenas para tipos definidos pelo usuário 1 . Ou seja, pelo menos um dos operandos deve ser do tipo definido pelo usuário. Como em outras funções sobrecarregadas, os operadores podem ser sobrecarregados para um determinado conjunto de parâmetros apenas uma vez.
Nem todos os operadores podem estar sobrecarregados em C ++. Entre os operadores que não podem ser sobrecarregados estão:
.
::
sizeof
typeid
.*
e o único operador ternário em C ++,?:
Entre os operadores que podem ser sobrecarregados em C ++ estão:
+
-
*
/
%
e+=
-=
*=
/=
%=
(todo o infixo binário);+
-
(prefixo unário);++
--
(prefixo unário e postfix)&
|
^
<<
>>
e&=
|=
^=
<<=
>>=
(todo o infixo binário);~
(prefixo unário)==
!=
<
>
<=
>=
||
&&
(todo o infixo binário);!
(prefixo unário)new
new[]
delete
delete[]
=
[]
->
->*
,
(todo o infixo binário);*
&
(prefixo todo unário)()
(chamada de função, infixo n-ário)No entanto, o fato de você poder sobrecarregar tudo isso não significa que você deve fazê-lo. Veja as regras básicas de sobrecarga do operador.
No C ++, os operadores são sobrecarregados na forma de funções com nomes especiais . Como em outras funções, operadores sobrecarregados geralmente podem ser implementados como uma função membro do tipo do operando esquerdo ou como funções não membros . Se você é livre para escolher ou obrigado a usar qualquer um deles depende de vários critérios. 2 Um operador unário
@
3 , aplicado a um objeto x, é chamado comooperator@(x)
ou comox.operator@()
. Um operador de infixo binário@
, aplicado aos objetosx
ey
, é chamado comooperator@(x,y)
ou comox.operator@(y)
. 4Às vezes, os operadores implementados como funções não membros são amigos do tipo de seu operando.
1 O termo "definido pelo usuário" pode ser um pouco enganador. O C ++ faz a distinção entre tipos internos e tipos definidos pelo usuário. Para os primeiros pertencem, por exemplo, int, char e double; a este último pertence todos os tipos de struct, classe, união e enum, incluindo os da biblioteca padrão, mesmo que não sejam, como tal, definidos pelos usuários.
2 Isso será abordado em uma parte posterior desta FAQ.
3 O
@
operador não é válido em C ++ e é por isso que o uso como espaço reservado.4 O único operador ternário em C ++ não pode ser sobrecarregado e o único operador n-ário deve sempre ser implementado como uma função membro.
Continue com as três regras básicas de sobrecarga de operadores em C ++ .
fonte
~
é prefixo unário, não infixo binário..*
está ausente na lista de operadores não sobrecarregáveis.:)
operator+()
como uma função membro, mas deu a assinatura de uma função livre. Veja aqui .A decisão entre membro e não membro
Os operadores binários
=
(atribuição),[]
(assinatura da matriz),->
(acesso de membro), bem como o()
operador n-ária (chamada de função), sempre devem ser implementados como funções de membro , porque a sintaxe do idioma exige isso.Outros operadores podem ser implementados como membros ou como não membros. Alguns deles, no entanto, geralmente precisam ser implementados como funções que não são membros, porque o operando esquerdo não pode ser modificado por você. Os mais destacados são os operadores de entrada e saída
<<
e>>
, cujos operandos esquerdos são classes de fluxo da biblioteca padrão que você não pode alterar.Para todos os operadores nos quais você deve optar por implementá-los como uma função membro ou não, use as seguintes regras práticas para decidir:
Obviamente, como em todas as regras de ouro, há exceções. Se você tem um tipo
e você deseja sobrecarregar os operadores de incremento e decremento, não é possível fazer isso como uma função membro, pois em C ++, os tipos de enumeração não podem ter funções membro. Então você precisa sobrecarregá-lo como uma função livre. E
operator<()
para um modelo de classe aninhado dentro de um modelo de classe é muito mais fácil escrever e ler quando executado como uma função de membro embutida na definição de classe. Mas essas são de fato raras exceções.(No entanto, se você fizer uma exceção, não se esqueça da questão de
const
-ness para o operando que, para funções-membro, se torna othis
argumento implícito . Se o operador como uma função não-membro usaria seu argumento mais à esquerda comoconst
referência , o mesmo operador que uma função membro precisa ter umconst
no final para fazer*this
umaconst
referência.)Continue com os operadores comuns para sobrecarregar .
fonte
operator+=()
não ser um membro. Ele precisa mudar seu operando do lado esquerdo, portanto, por definição, precisa se aprofundar em suas entranhas. O que você ganharia se não fosse um membro?operator +=
osappend
métodos e. Oappend
método é mais completo, porque você pode anexar uma substring do parâmetro do índice i ao índice n -1:append(string, start, end)
parece lógico ter+=
o acréscimo de chamada comstart = 0
eend = string.size
. Nesse momento, o acréscimo poderia ser um método de membro, masoperator +=
não precisa ser um membro, e torná-lo um não-membro diminuiria a quantidade de código reproduzida com as entranhas String, por isso é uma coisa boa ... ^ _ ^ ...Operadores de conversão (também conhecidos como conversões definidas pelo usuário)
No C ++, você pode criar operadores de conversão, operadores que permitem a conversão do compilador entre seus tipos e outros tipos definidos. Existem dois tipos de operadores de conversão, implícitos e explícitos.
Operadores implícitos de conversão (C ++ 98 / C ++ 03 e C ++ 11)
Um operador de conversão implícita permite que o compilador converta implicitamente (como a conversão entre
int
elong
) o valor de um tipo definido pelo usuário para outro tipo.A seguir, é apresentada uma classe simples com um operador de conversão implícito:
Operadores de conversão implícitos, como construtores de um argumento, são conversões definidas pelo usuário. Os compiladores concederão uma conversão definida pelo usuário ao tentar corresponder uma chamada a uma função sobrecarregada.
No começo, isso parece muito útil, mas o problema é que a conversão implícita entra em ação quando não se espera. No código a seguir,
void f(const char*)
será chamado porquemy_string()
não é um lvalue ; portanto, o primeiro não corresponde:Iniciantes facilmente entendem isso errado e até programadores C ++ experientes às vezes são surpreendidos porque o compilador pega uma sobrecarga que não suspeitava. Esses problemas podem ser atenuados por operadores de conversão explícitos.
Operadores de conversão explícita (C ++ 11)
Ao contrário dos operadores de conversão implícitos, os operadores de conversão explícitos nunca entram em ação quando você não espera. A seguir, uma classe simples com um operador de conversão explícito:
Observe o
explicit
. Agora, quando você tenta executar o código inesperado dos operadores de conversão implícitos, obtém um erro do compilador:Para chamar o operador de conversão explícita, você deve usar
static_cast
uma conversão no estilo C ou uma conversão no estilo construtor (ou sejaT(value)
).No entanto, há uma exceção a isso: O compilador pode converter implicitamente em
bool
. Além disso, o compilador não tem permissão para fazer outra conversão implícita depois de converter parabool
(um compilador pode fazer 2 conversões implícitas por vez, mas apenas 1 conversão definida pelo usuário no máximo).Como o compilador não converterá "passado"
bool
, os operadores de conversão explícita agora eliminam a necessidade do idioma Safe Bool . Por exemplo, ponteiros inteligentes antes do C ++ 11 usavam o idioma Safe Bool para impedir conversões em tipos integrais. No C ++ 11, os ponteiros inteligentes usam um operador explícito porque o compilador não tem permissão para converter implicitamente em um tipo integral depois de converter explicitamente um tipo em bool.Continue com Sobrecarga
new
edelete
.fonte
Sobrecarga
new
edelete
Nota: Isso lida apenas com a sintaxe de sobrecarga
new
edelete
, não com a implementação desses operadores sobrecarregados. Eu acho que a semântica da sobrecarganew
edelete
merece sua própria FAQ , dentro do tópico sobrecarga do operador, nunca posso fazer justiça.Fundamentos
Em C ++, quando você escrever uma nova expressão como
new T(arg)
duas coisas acontecem quando esta expressão é avaliada: Primeirooperator new
é invocado para obter a memória bruta, e, em seguida, o construtor adequada deT
é invocado para transformar esta memória bruto em um objeto válido. Da mesma forma, quando você exclui um objeto, primeiro seu destruidor é chamado e, em seguida, a memória é retornadaoperator delete
.O C ++ permite ajustar essas duas operações: gerenciamento de memória e construção / destruição do objeto na memória alocada. O último é feito escrevendo construtores e destruidores para uma classe. O gerenciamento de ajuste de memória é feito escrevendo seu próprio
operator new
eoperator delete
.A primeira das regras básicas da sobrecarga do operador - não faça isso - se aplica especialmente à sobrecarga
new
edelete
. Quase os únicos motivos para sobrecarregar esses operadores são problemas de desempenho e restrições de memória e , em muitos casos, outras ações, como alterações nos algoritmos utilizados, fornecerão uma relação custo / ganho muito maior do que tentar ajustar o gerenciamento de memória.A biblioteca padrão C ++ vem com um conjunto de operadores
new
e predefinidosdelete
. Os mais importantes são estes:Os dois primeiros alocam / desalocam memória para um objeto, os dois últimos para uma matriz de objetos. Se você fornecer suas próprias versões, elas não sobrecarregarão, mas substituirão as da biblioteca padrão.
Se você sobrecarregar
operator new
, sempre sobrecarregue a correspondênciaoperator delete
, mesmo que nunca pretenda chamá-la. O motivo é que, se um construtor lança durante a avaliação de uma nova expressão, o sistema de tempo de execução retornará a memória para aoperator delete
correspondênciaoperator new
que foi chamada para alocar a memória para a criação do objeto. Se você não fornecer uma correspondênciaoperator delete
, o padrão é chamado, o que quase sempre está errado.Se você sobrecarregar
new
edelete
, também deverá sobrecarregar as variantes da matriz.Canal
new
O C ++ permite que operadores novos e excluídos recebam argumentos adicionais.
O chamado posicionamento new permite criar um objeto em um determinado endereço que é passado para:
A biblioteca padrão vem com as sobrecargas apropriadas dos operadores new e delete para isso:
Observe que, no código de exemplo para posicionamento novo fornecido acima,
operator delete
nunca é chamado, a menos que o construtor de X gere uma exceção.Você também pode sobrecarregar
new
edelete
com outros argumentos. Como no argumento adicional para posicionamento novo, esses argumentos também são listados entre parênteses após a palavra-chavenew
. Apenas por razões históricas, essas variantes também são chamadas de posicionamento novo, mesmo que seus argumentos não sejam para colocar um objeto em um endereço específico.Novo e excluir específico da classe
Geralmente, você deseja ajustar o gerenciamento de memória porque a medição mostrou que as instâncias de uma classe específica ou de um grupo de classes relacionadas são criadas e destruídas frequentemente e que o gerenciamento de memória padrão do sistema de tempo de execução, ajustado para desempenho geral, lida de forma ineficiente nesse caso específico. Para melhorar isso, você pode sobrecarregar new e delete para uma classe específica:
Sobrecarregado, assim, new e delete se comportam como funções de membro estáticas. Para objetos de
my_class
, ostd::size_t
argumento sempre serásizeof(my_class)
. No entanto, esses operadores também são chamados para objetos alocados dinamicamente de classes derivadas ; nesse caso, pode ser maior que isso.Novo global e exclusão
Para sobrecarregar o novo global e excluir, basta substituir os operadores predefinidos da biblioteca padrão pelos nossos. No entanto, isso raramente precisa ser feito.
fonte
nothrow
novas.Por que a
operator<<
função de transmitir objetos parastd::cout
ou para um arquivo não pode ser uma função membro?Digamos que você tenha:
Dado isso, você não pode usar:
Como
operator<<
está sobrecarregado como uma função membro deFoo
, o LHS do operador deve ser umFoo
objeto. O que significa que você precisará usar:o que é muito não intuitivo.
Se você defini-lo como uma função não membro,
Você poderá usar:
o que é muito intuitivo.
fonte