Guia Para Estilo de Código C++ Pesquisa e Desenvolvimento Tecnológico



Documentos relacionados
Computação II Orientação a Objetos

Implementando uma Classe e Criando Objetos a partir dela

Programação Orientada a Objetos C++

Conceitos básicos da linguagem C

Linguagem de Programação JAVA. Técnico em Informática Professora Michelle Nery

Programação Estruturada. Programação Estruturada. Idéias Básicas da Programação Estruturada

Templates. Introdução. Motivação. Thiago Rosso Adams

PROGRAMAÇÃO ORIENTADA A OBJETO EM PHP

3.1 Definições Uma classe é a descrição de um tipo de objeto.

TÉCNICAS DE PROGRAMAÇÃO

2 Ferramentas Utilizadas

Resolução da lista de exercícios de casos de uso

Linguagens de Programação Aula 10

Orientação a Objetos

Introdução a Java. Hélder Nunes

Exercícios de Revisão Java Básico

Sistemas Operacionais. Prof. André Y. Kusumoto

Desenvolvimento OO com Java Orientação a objetos básica

Trabalho 3: Agenda de Tarefas

Programação por Objectos. Java

9 Comandos condicionais

LISTA DE VERIFICAÇAO DO SISTEMA DE GESTAO DA QUALIDADE

Linguagens de Programação

Um objeto é uma instância de uma 'classe'. Você define uma classe utilizando o trecho de código abaixo;

BACHARELADO EM SISTEMAS DE INFORMAÇÃO EaD UAB/UFSCar Sistemas de Informação - prof. Dr. Hélio Crestana Guardia

ATRIBUTOS PRIVADOS 6. ENCAPSULAMENTO MÉTODOS PRIVADOS MÉTODOS PRIVADOS

agility made possible

Tabela de Símbolos. Análise Semântica A Tabela de Símbolos. Principais Operações. Estrutura da Tabela de Símbolos. Declarações 11/6/2008

ÍNDICE. Delphi... 3 CAPÍTULO 1 INTRODUÇÃO CAPÍTULO 2 INSTALANDO O DELPHI... 10

Migrando para o Word 2010

Prof. Jhonatan Fernando

5 Apresentando a linguagem C

Introdução a POO. Introdução a Linguagem C++ e POO

UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL INSTITUTO DE INFORMÁTICA INFORMÁTICA APLICADA

Sumário. Parte I Filosofia e Modelagem Orientada a Objetos... 23

Engenharia de Software II

Linguagem de Programação III

Integração de livros fiscais com o Microsoft Dynamics AX 2009

Figure 2 - Nós folhas de uma árvore binária representando caracteres ASCII

INTRODUÇÃO À LINGUAGEM C++

Princípios de programação em Linguagem C++

3 Qualidade de Software

Portal do Projeto Tempo de Ser

Engenharia de Software e Gerência de Projetos Prof. Esp. André Luís Belini Bacharel em Sistemas de Informações MBA em Gestão Estratégica de Negócios

Bem-vindo ao tópico Múltiplas filiais.

INTRODUÇÃO AO C++ SISTEMAS DE INFORMAÇÃO DR. EDNALDO B. PIZZOLATO

Análise e Projeto Orientados por Objetos

UNIVERSIDADE FEDERAL DE SANTA MARIA CENTRO DE TECNOLOGIA AULA 14 PROFª BRUNO CALEGARO

Capítulo 2. Processos de Software Pearson Prentice Hall. Todos os direitos reservados. slide 1

O mecanismo de alocação da CPU para execução de processos constitui a base dos sistemas operacionais multiprogramados.

Indústria de Cartões de Pagamento (PCI) Padrão de segurança de dados. Resumo de Alterações da Versão 2.0 para a 3.0 do PCI-DSS

Algoritmos e Programação II. Sobrecarga

Guia de utilização da notação BPMN

Metadados. 1. Introdução. 2. O que são Metadados? 3. O Valor dos Metadados

O Princípio da Complementaridade e o papel do observador na Mecânica Quântica

Programação Orientada a Objetos. Prof. Diemesleno Souza Carvalho diemesleno@iftm.edu.br

Copyright Proibida Reprodução. Prof. Éder Clementino dos Santos

5 - Vetores e Matrizes Linguagem C CAPÍTULO 5 VETORES E MATRIZES

Exercícios Teóricos Resolvidos

Reuso com Herança a e Composiçã

SOP - TADS Sistemas de Arquivos Cap 4 Tanenmbaum

Montagem e Manutenção. Luís Guilherme A. Pontes

CONVENÇÃO DE CÓDIGO JAVA

PowerPoint 2010 para o Office 365 para empresas

TRANSMISSÃO DE DADOS Prof. Ricardo Rodrigues Barcelar

ISO/IEC Avaliação da conformidade Declaração de conformidade do fornecedor Parte 1: Requisitos gerais

Especificação do Trabalho Prático

cast poderia ser usado também para transformar um real (float) em inteiro. A sintaxe C (float)i pode ser substituída em C++ por float(i).

Tópicos Avançados em Banco de Dados Gerenciamento de Transações em Banco de Dados. Prof. Hugo Souza

3 A Biblioteca para Implementação de Máquinas Virtuais

Configurando a emissão de boletos no sistema

Programação Orientada a Objetos e Java - Introdução. Carlos Lopes

BC0505 Processamento da Informação

Resolução de sistemas lineares

Computador Digital Circuitos de um computador (Hardware)

Manual do Usuário - ProJuris Web - Biblioteca Jurídica Página 1 de 20

Guia de Fatores de Qualidade de OO e Java

CADERNOS DE INFORMÁTICA Nº 1. Fundamentos de Informática I - Word Sumário

PROGRAMAÇÃO ESTRUTURADA. CC 2º Período

Tabelas vista de estrutura

Aula de JavaScript 05/03/10

1 Funções básicas de implementação de arquivos

Q-Acadêmico. Módulo CIEE - Estágio. Revisão 01

Energia Eólica. Atividade de Aprendizagem 3. Eixo(s) temático(s) Ciência e tecnologia / vida e ambiente

NORMA BRASILEIRA DE CONTABILIDADE NBC TSC 4410, DE 30 DE AGOSTO DE 2013

Manual do Usuário. Sistema para Administração de Condomínios MANUAL USUÁRIO. Bancos do Condomínio. ENG Sistemas - 1 -

Tutorial: Aprenda a criar seu próprio makefile. Darcamo (Forúns Ubuntu)

Programação Orientada a Objetos Herança Técnico em Informática. Prof. Marcos André Pisching, M.Sc.

Java 2 Standard Edition Como criar classes e objetos

UML & Padrões Aula 3. UML e Padrões - Profª Kelly Christine C. Silva

Teclado. Mike McBride Anne-Marie Mahfouf Tradução: Lisiane Sztoltz

Tutorial 7 Fóruns no Moodle

Início Rápido para o Templo

Análise de Programação

Aula 12: Funções. Pré-requisitos: Todas as aulas anteriores deste módulo. 1. Aproveitando Códigos no Programa

Aula 4 Estatística Conceitos básicos

Algoritmos e Programação

Transcrição:

Guia Para Estilo de Código C++ Pesquisa e Desenvolvimento Tecnológico

2 Pesquisa e Desenvolvimento Tecnológico Essa página foi deixada em branco intencionalmente.

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 3 PUBLICADO POR Atual Sistemas Departamento de Desenvolvimento A informação contida neste documento representa a visão então sustentada pela Atual Sistemas sobre os assuntos abordados na data de publicação do mesmo. Uma vez que a Atual Sistemas reagirá à mudanças nas condições do mercado, este documento não deve ser interpretado como sob compromisso por parte da Atual Sistemas, e a Atual Sistemas não garante exatidão de qualquer informação apresentada após a data dessa publicação. As informações aqui contidas são apenas para propósito informativo. A Atual Sistemas NÃO FORNECE NENHUMA GARANTIA OU RESPONSABILIDADE QUANTO A INFORMAÇÃO NESSE DOCUMENTO. Esse documento é uma obra intelectual de uso restrito ao departamento de desenvolvimento da Atual Sistemas não podendo ser reproduzido, armazenado, alterado, distribuído em quaisquer que sejam os meios (eletrônico, mecânico, fotocopiado, gravado ou qualquer que seja), quer completo, quer parcial, para qualquer propósito, sem uma expressa autorização escrita da Atual Sistemas. A violação desse acordo por posse ou uso não autorizado em quaisquer das situações citadas acima representa um ato direto contra os direitos de cópia e direitos de intelectualidade e será respondida conforme o rigor da lei. 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

4 Pesquisa e Desenvolvimento Tecnológico Sumário PUBLICADO POR... 3 GUIA PARA ESTILO DE CÓDIGO C++... 6 ARQUIVOS CABEÇALHO... 6 A PROTEÇÃO #DEFINE...6 DEPENDÊNCIAS DOS ARQUIVOS CABEÇALHOS... 7 FUNÇÕES INLINE... 7 ORDEM PARA PARÂMETROS DE FUNÇÕES... 8 NOMES E ORDEM DE INCLUSÃO... 8 ESCOPOS... 9 NAMESPACES ANÔNIMOS...9 NAMESPACES IDENTIFICADOS... 10 CLASSES ANINHADAS... 11 NÃO-MEMBRO, MEMBRO ESTÁTICO, E FUNÇÕES GLOBAIS... 11 VARIÁVEIS LOCAIS... 12 VARIÁVEIS ESTÁTICAS E GLOBAIS... 13 CLASSES... 13 CONTRUTORES O QUE FAZER NELES... 13 CONSTRUTOR PADRÃO... 14 CONSTRUTOR EXPLÍCITO... 14 CONSTRUTOR DE CÓPIA... 15 STRUCTS VERSUS CLASSE... 16 HERANÇA... 16 HERANÇA MULTIPLA... 17 INTERFACES... 17 SOBRECARGA DE OPERADORES... 18 CONTROLE DE ACESSO... 18 ESCREVA FUNÇÕES CURTAS... 19 OUTROS RECURSOS C++... 19 ARGUMENTOS REFERÊNCIAS... 19 SOBRECARGA DE FUNÇÕES... 20 ALGUMENTOS DEFAULT... 20 ARRAYS DE TAMANHO VARIÁVEL E ALLOCA()... 21 FRIENDS... 21 EXCEÇÕES... 21 RUN-TIME TYPE INFORMATION (RTTI)... 22 CASTING... 23 STREAMS... 23 PRÉ-INCREMENTO E PRÉ-DECREMENTO... 24 USO DE CONST... 25 TIPOS INTEIROS... 26 MACROS DO PRÉ-PROCESSADOR... 27 0 E NULLPTR... 27 SIZEOF... 27

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 5 C++11... 27 NOMES... 28 NOMES DE ARQUIVOS... 29 NOMES DE TIPOS... 29 NOMES DE VARIÁVEIS... 30 NOMES DE CONSTANTES... 30 NOMES DE FUNÇÕES... 30 NOMES DE NAMESPACES... 31 NOMES DE ENUMERADORES... 31 NOMES DE MACROS... 31 EXCESSÕES A REGRA... 31 COMENTÁRIOS... 31 ESTILO DE COMENTÁRIO... 32 COMENTÁRIO DO ARQUIVO... 32 COMENTÁRIOS DE CLASSE... 33 COMENTÁRIOS DE FUNÇÕES E MÉTODOS... 33 COMENTÁRIOS DE VARIÁVEIS... 34 COMENTÁRIOS COMPLEMENTARES... 35 PONTUAÇÃO, ORTOGRAFIA E GRAMÁTICA... 36 COMENTÁRIOS HACK E TODO... 36 COMENTÁRIOS DE DEPRECIAÇÃO... 37 FORMATAÇÃO... 37 TAMANHO DE LINHA... 37 CARACTERES NÃO-ASCII... 38 ESPAÇOS VERSUS TABS... 38 DECLARAÇÃO E DEFINIÇÃO DE FUNÇÕES... 38 CHAMADAS DE FUNÇÕES... 39 CONDICIONAIS... 39 LOOP E SWITCHES... 40 PONTEIRO E REFERÊNCIA... 41 EXPRESSÕES BOOLEANAS... 41 VALORES DE RETORNO... 41 INICIALIZAÇÃO DE ARRAYS E DE VARIÁVEIS... 42 DIRETIVAS DE PRÉ-PROCESSADOR... 42 FORMATO DE CLASSE... 42 LISTA DE INICIALIZADORES DO CONSTRUTOR... 43 FORMATAÇÃO DE NAMESPACE... 43 ESPAÇOS HORIZONTAIS... 43 ESPAÇOS VERTICAIS... 44 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

6 Pesquisa e Desenvolvimento Tecnológico Guia Para Estilo de Código C++ C++ é a linguagem escolhida para se tornar a principal linguagem de desenvolvimento usado nos projetos da Atual Sistemas. Como todo programador C++ sabe, a linguagem possuem muitas características poderosas, mas esse poder traz também complexidade, o que por sua vez, pode tornar o código mais propenso a bugs e mais difícil de ler e manter. O objetivo desse manual é ajudar a lidar com essa complexidade por descrever em detalhes o que fazer e o que não fazer ao escrever código C++. Essas regras existem para manter a base de código administrável enquanto permite que outros desenvolvedores use recursos da linguagem C++ de modo produtivo. O estilo, também conhecido como legibilidade, é o que nós chamamos de padrão que governa o nosso código C++. O termo estilo aqui acaba sendo mais abrangente, visto que esse padrão aborda muito mais assuntos que apenas formatação de arquivos. Uma das formas de se manter a base de código administrável é por se enfatizar a consistência. É muito importante que cada programador possa olhar e entender o código de outro programador rapidamente. Manter um estilo uniforme e seguir padrões nos possibilita usar a similaridade em padrões para deduzir o que cada símbolo representa e quais constantes são verdadeiras sobre eles. Criar padrões e dialetos em comum, torna o código mais fácil de entender. Em alguns casos pode se haver alguma argumentação para se altera uma regra de estilo, mas é preferível manter as coisas conforme padronizadas para preservar a consistência. Outra questão abordada nesse guia está relacionado ao excesso de recursos providos em C++. A linguagem C++ é gigantesca como muitos recursos avançados. Em alguns casos, é preferível restringir ou até banir o uso de certos recursos. Nós fazemos isso para manter o código simples e para evitar os vários problemas e erros comuns que essas características podem causar. Esse guia lista esses recursos e explica porque eles são proibidos. Note que esse guia não é um tutorial de C++: não são dados detalhes minuciosos porque se assume que o leitor já está familiarizado. Como regra geral para esses estilo de código, seja consistente. Siga o estilo já existente no resto do código, e essas regras serão intuitivas. Se você está editando código já existente, tome alguns minutos para olhar no código ao redor e assim determinar qual é o estilo de código usado. O objetivo de se ter um guia de estilo de código é ter um vocabulário em comum de modo que você possa se concentrar no que está sendo dito, ao invés de se concentrar em como está sendo dito. Arquivos Cabeçalho Na prática, todo arquivo.cpp deve ter um arquivo.h associado. Há algumas exceções comuns, tais como unidades de testes e alguns arquivos pequenos.cpp contendo apenas uma função min(). O uso correto de arquivos cabeçalhos pode representar uma imensa diferença entre a legibilidade, tamanho e performance do seu código. As seguintes regras o guiarão para evitar as muitas armadilhas ao usar arquivos cabeçalhos. A proteção #define Todos os arquivos cabeçalho devem usar a proteção #define para evitar múltiplas inclusões. O formato do nome do símbolo deve ser <PROJETO>_<CAMINHO>_<ARQUIVO>_H_. Para garantir a singularidade do símbolo usado, deve ser usado o caminho completo na árvore de arquivos do projeto. Por exemplo, o arquivo foo/src/bar/baz.h no projeto foo deveria ter a seguinte proteção:

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 7 #ifndef FOO_BAR_BAZ_H_ #define FOO_BAR_BAZ_H_... #endif// FOO_BAR_BAZ_H_ Dependências dos arquivos cabeçalhos Não use #include quando um declaração forward serviria. Quando você inclui um arquivo cabeçalho você introduz uma dependência que fará que seu código seja recompilado sempre que o arquivo cabeçalho mudar. Se arquivo cabeçalho inclui outros arquivos cabeçalhos, qualquer mudança nesses arquivos cabeçalhos fará com que todo código que inclui o seu arquivo cabeçalho seja recompilado também. Por essa razão, nós preferimos minimizar as inclusões, principalmente a inclusão de cabeçalhos em outros cabeçalhos. Você reduzir significantemente o número de arquivos cabeçalhos para inclusão no seus próprios arquivos cabeçalhos por usar forward declaration. Por exemplo, se seu arquivo cabeçalho usa a classe File, você pode simplesmente usa uma forward declaration class File; ao invés de ter de usar #include file/base/file.h. Como fazer para usar uma classe Foo em um arquivo cabeçalho sem acessar suas definições? Nós podemos declarar dados membros do tipo Foo* ou Foo&. Nós podemos declarar (mas não podemos definir) funções com argumentos, e/ou valores de retorno, do tipo Foo. (Uma exceção é se um argumento Foo ou const Foo& possuem um construtor não explícito de apenas um argumento que, em casos como esse, requer uma definição completa para suportar a conversão de tipo automática.) Nós podemos declarar dados membros estáticos do tipo Foo. Isso se dá porque dados membros estáticos são definidos fora da definição da classe. Por outro lado, você terá que incluir o arquivo cabeçalho para Foo seu sua classe é uma subclasse de Foo ou se sua classe usa dados membros do tipo Foo. Em alguns casos faz sentido ter membros ponteiro (ou melhor, scoped_ptr ou unique_ptr) ao invés de objetos. No entanto, isso complica a legibilidade do código e gera uma penalidade na performance. Assim, evite fazer essa mudança se o único propósito é minimizar includes nos arquivos cabeçalhos. É claro, arquivos.cpp normalmente vão requerer as definições da classe que eles usam e por isso vão ter de incluir diversos arquivos. Atenção: Se você usa um símbolo Foo no seu arquivo fonte, você terá de se encarregar em trazer a definição de Foo, quer via um #include ou via uma forward declaration. Não dependa de símbolos introduzidos transitivamente por cabeçalhos não incluídos diretamente. Uma exceção é se Foo é usada em meuarquivo.cpp. Neste caso, não tem problema usar #include (ou forward declaration) para Foo em meu meuarquivo.h, ao invés de fazer a inclusão em meuarquivo.cpp. Atenção: Não omita o nome dos parâmetros nos protótipos das funções. Funções inline Defina funções inline somente quando eles foram pequenas, como 10 linhas ou menos. 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

8 Pesquisa e Desenvolvimento Tecnológico Definição Você pode declarar funções de uma modo que permite o compilador expandí-las na linha usada ao invés de chamálas usando o mecanismo natural de chamada de funções. Prós Funções inline podem gerar um código mais eficiente, contanto que a função inline seja curta. Sinta-se livre para declarar assessores e mutadores como inline, e também funções curtas que são críticas para performance. O uso excessivo de inline pode na verdade deixar o programa mais lento. Dependendo do tamanho da função, tornar ela inline pode aumentar ou diminuir o tamanho do código. Uma função inline assessor pequena normalmente diminuirá o tamanho do código ao passo que uma função inline grande pode aumentar o tamanho do código dramaticamente. Em processadores modernos, código pequeno normalmente roda mais rápido devido ao melhor uso de cache. Uma boa regra é não criar funções inline que possuem mais de dez linhas de código. Fique atento quanto aos destrutores, os quais são normalmente maiores do que aparentam devido a chamada implícita de destrutores base e membros. Outra boa regra: normalmente não é muito eficaz criar funções inline que usam loops ou instruções switch (a menos que, no casos mais comum, o loop ou a instrução switch não são executados). É importante atentar ao fato que nem sempre funções declaradas como inline serão consideradas como inline. Por exemplo, funções virtuais ou funções recursivas normalmente não serão inline. Em geral, funções recursivas não podem ser inline. A principal razão para criar uma função virtual inline é para colocar sua definição na classe, quer isso seja por coveniência ou para documentar o comportamento, como no caso de acessores e mutadores. Ordem para parâmetros de funções Ao definir uma função a ordem dos parâmetros é: entrada e depois saída. Em C/C++, parâmetros de funções são tanto entrada para a função, saída da função, ou ambos. Parâmetros de entrada normalmente são valores ou são referências const, enquanto parâmetros de saída e parâmetros de entrada/saída serão ponteiros não-const. Ao ordenar os parâmetros de uma função, coloque todos os parâmetros somente-leitura antes de todos os parâmetros de saída. Em particular, não adicione novos parâmetros ao fim da função só porque eles são novos. Coloque novos parâmetros de entrada antes dos de saída. Essa não é uma regra completamente inflexível. Parâmetros que são tanto entrada e saída (como quando se passa classes/estruturas) complicam essa regra e, como sempre, manter consistência com outras funções relacionadas pode requerer que você desobedeça essa regra. Principalmente em casos de programação estruturada que se assemelha a OO em C. Nomes e ordem de inclusão Use a ordem padrão por questão de legibilidade e evite dependências escondidas: Bibliotecas C, bibliotecas C++, outras bibliotecas.h e por fim os.h do seu projeto. Todos os arquivos cabeçalhos devem ser incluídos seguindo o caminho do diretório raiz do projeto, não sendo permitido o uso dos atalhos UNIX. (o diretório corrente) ou.. (o diretório pai). Por exemplo, o arquivo projetoatual/src/base/logging.h deve ser incluído como no caso abaixo.

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 9 #include "base/logging.h" Assim, no arquivo dir/foo.cpp ou dir/foo_test.cpp, cujo principal objetivo é implementar ou testar o conteúdo de dir2/foo2h.h, ordene seus includes da maneir a a seguir. 1. dir2/foo2h.h (tem localização preferencial veja detalhes abaixo). 2. Arquivos de sistema C. 3. Arquivos de sistema C++. 4. Arquivos.h de outras bibliotecas. 5. Arquivos.h do seu projeto. Tendo essa ordem preferencial, se dir2/foo2h.h omite inclusões necessárias, o build de dir/foo.cpp ou dir/foo_test.cpp será quebrado. Assim, esta regra garante que o build quebre primeiro para as pessoas trabalhando nesses arquivos, ao invés de ocorrer para outros desenvolvedores que não possuem conhecimento de tais arquivos. dir/foo.cpp e dir2/foo2.h geralmente estarão no mesmo diretório, mas você pode colocá-los em diretórios diferentes também. Dentro de cada seção, é interessante que os cabeçalhos seja incluídos em ordem alfabética. Por exemplo, os includes de projeto-atual/src/foo/interno/fooserver.cpp pode ser da seguinte forma: #include "foo/publico/fooserver.h" // Preferred location. #include <sys/types.h> #include <unistd.h> #include <hash_map> #include <vector> #include "base/basictypes.h" #include "base/commandlineflags.h" #include "foo/publico/bar.h" Escopos A discução sobre escopos é bem extensa e será dividida em tópicos. Namespaces Anônimos Namespaces anônimos são permitidos e até mesmo encorajados em arquivos cpp, para se evitar conflitos de nomes durante a execução. namespace { // Este é um arquivo cpp. // O conteúdo do namespace não tem identação enum { knaousado, keof, kerror ; // tokens usados. bool AtEof() { return pos_ == keof; // Uso de keof do nosso namespace. // namespace Entretanto, declarações no escopo do arquivo que estão relacionadas com uma classe em particular desse arquivo podem ser declaradas nessa classe como tipos, dados membros estáticos ou funções membro estáticas. Esse método é preferível em lugar de namespaces anônimos. Não use namespaces anônimos em arquivos.h. 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

10 Pesquisa e Desenvolvimento Tecnológico Namespaces Identificados Namespaces identificados devem ser usados do seguinte modo: Namespaces abrangerão todo o conteúdo do arquivo fonte após os includes e as forward declarations de classes de outros namespaces. // No arquivo.h namespace meunamespace { // Todas as declarações estão dentro do escopo do namespace. // Note que não é usada indentação. class MinhaClasse { public:... void Foo(); ; // namespace meunamespace // No arquivo.cpp namespace meunamespace { // A definição de funções fica dentro do escopo do namespace void MinhaClasse::Foo() {... // namespace meunamespace Um arquivo.cpp típico pode ter detalhes mais complexos, o que inclui a necessidade de referenciar classes em outros namespaces. #include "a.h" class C; // Forward declaration para a classe C no escopo global. namespace a { class A; // Forward declaration para a classe a::a. namespace b {...codigo de b... // namespace b Não declare nada no namespace std, nem faça nem mesmo forward declarations de elementos da std. Declarar elementos no namespace std leva a um comportamento imprevisível. Para declara elementos da std, inclua o arquivo cabeçalho apropriado. Não use a diretiva using para tornar visível todos os nomes de um namespace. // Proibido - Isso polui o namespace. using namespace foo; Você pode usar a diretiva using em qualquer lugar em um arquivo.cpp, ou em funções, métodos ou classes em um arquivo.h. // OK usar em aquivos.cpp. // Em arquivos.h, deve estar dentro de uma função, método ou classe. using ::foo::bar; Alias para namespaces são permitidos em qualquer lugar em um aquivo.cc, em qualquer lugar dentro de um namespace identificado que abrange um arquivo.h inteiro, e em funções e métodos. // Acesso abreviado a alguns nomes comuns no arquivo.cpp.

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 11 namespace fbz = ::foo::bar::baz; // Acesso abreviado a alguns nomes comuns usados (em um arquivo.h). namespace biblioteca { // O seguinte alias está disponível para todos os arquivo incluindo // esse cabeçalho (dentro do namespace biblioteca). // Por essa razão, nomes alias devem ser escolhidos de modo // consistente em todo o projeto. namespace pd_s = ::pipeline_diagnostics::sidetable; inline void minha_funcao_inline() { // alias de um nomespace local apenas para a função. namespace fbz = ::foo::bar::baz;... // namespace biblioteca Note que um alias em um arquivo.h é visível a todos os que incluem esse arquivo, de modo que cabeçalhos públicos (os que ficam disponíveis fora de um projeto) e os cabeçalhos incluídos por esses arquivo devem evitar definir alias, como parte de objetivo geral de manter uma API pública com o menor tamanho possível. Classes Aninhadas Embora você possa usar classes aninhadas públicas quando elas fazem parte de uma interface, verifique se não seria melhor usar um namespace para manter a declaração fora do escopo global. Definição Uma classe pode definir outra classe dentro dela, o que é chamado também de classe membro. class Foo { private: // Bar é uma classe membro, aninhada dentro de foo. class Bar {... ; ; Prós Isso é útil quando a classe aninhada (ou membro) é usada apenas pela classe que a aninhou. Criar uma classe membro faz com que essa classe se limite ao escopo da classe que a criou ao invés de poluir o escopo externo com o nome da classe. Classes aninhadas podem ser definidas com uma forward declaration na classe origem e depois definidas no arquivo.cpp para evitar que as definições da classe aninhada sejam necessárias a classe que a possue. Classes aninhadas só podem ser usadas com forward declaration dentro da definição da classe que a possue. Assim, qualquer cabeçalho usando um ponteiro Foo::Bar* terá de incluir a definição inteira da classe Foo. Não faça com que classes aninhadas sejam públicas a menos que elas realmente façam parte da interface, como por exemplo, uma classe que traz um conjunto de opção para algum método. Não-membro, Membro Estático, e Funções Globais Dê preferência ao uso de funções não-membro dentro de um namespace ou a funções membro estáticas em lugar de funções membros globais. O uso de funções completamente globais deve ser raro. 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

12 Pesquisa e Desenvolvimento Tecnológico Prós Funções não-membro e funções membro estáticas podem ser muito úteis em algumas situações. Colocar funções não-membro em um namespace evitar poluir o namespace global. Funções não-membro e funções membro estáticas fazem mais sentido como membros de uma nova classe, especialmente se elas acessam recursos externos ou possuem um número significativo de dependências. Algumas veses é útil, ou até mesmo necessário, definir funções que não estão presas a instância de alguma classe. Tal função pode ser tanto uma função membro estática ou uma função não-membro. Funções não-membro não devem depender de variáveis externas, e devem semprer existir dentro de um namespace. Ao invés de criar classes somente para agrupar funções membro estáticas as quais não compartilham dados estáticos, use namespaces. Funções definidas na mesma unidade de compilação que classes usadas em produção podem introduzir dependências em tempo de link desnecessárias quando chamadas diretamente de outras unidades de compilação. Em particular, funções membro estáticas são muito suscetíveis a esse problema. Se você precisa definir uma função não-membro e ela será necessária somente no aquivo.cpp, use um namespace estático ou use linkagem estática (ex. static int foo() {...) para limitar o escopo da função. Variáveis locais Coloque uma variável local no escopo mais próximo do seu uso que for possível, e inicialize as variáveis na declaração. C++ lhe permite declarar variáveis em qualquer lugar em uma função. Nós o encorajamos a declarar variáveis no escopo mais local quanto for possível, e mais próximo do primeiro uso dessa variável quanto for possível. Isso torna mais fácil para um programador achar a declaração e ver qual é o tipo da variável e qual valor inicial foi atribuído. Em particular, deve-se usar inicialização ao invés de declaração seguida de atribuição. int i; i = f(); // Ruim -- inicialização separada da declaração. int j = g(); // Bom -- declaraçao com inicialização. Note que o gcc e o MSVC implementam for (int i = 0; i < 10; ++i) corretamente (o escopo de i é limitado ao escopo do loop for), de modo que você pode reusar i em outro loop for no mesmo escopo. Esses compiladores também controlam corretamente o escopo em instruções if e while. while (const char* p = strchr(str, '/')) str = p + 1; No entanto há uma palavra de cautela: se a variável é um objeto, seu construtor é chamado toda vez que se entra no escopo, e o destrutor é chamado toda vez que se sai do escopo. // Implementação ineficiente: for (int i = 0; i < 1000000; ++i) { Foo f; // Meu construtor e destrutor esão send chamados 1000000 vezes. f.dosomething(i); Em casos como esse, será mais eficiente declarar tal variável fora do escopo do loop. Foo f; // Meu construtor e destrutor chamados só uma vez. for (int i = 0; i < 1000000; ++i) { f.dosomething(i);

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 13 Variáveis Estáticas e Globais Variáveis estáticas ou globais cujos tipos são classes estão proibidas. Elas causam bugs difíceis de achar devido a ordem inderteminada de criação e destruição. Objetos com duração de armazenamento estático, o que inclui variáveis globais, variáveis estáticas, membros estáticos de classes e variáveis estáticas de funções devem ser Plain Old Data (POD). Somente ints, chars, ponteiros ou arrays e structs POD podem ser usados para armazenamento estático. A ordem em que construtores de classes para variáveis de classes são chamados é difinido parcialmente em C++ e pode mudar até mesmo de build para build, o que pode causar bugs difíceis de achar. Portanto, além de banir o uso de globais cujos tipos são classes, nós não permitimos também que variáveis POD sejam inicializadas com o resultado de uma função, a menos que essa função não dependa de qualquer dado global (como no caso de getenv() ou getpid()). De modo similar, a ordem em que os destrutores são chamados é definida reversamente a ordem que os construtores foram chamados. Levando em conta que a ordem dos construtores é indeterminada, o mesmo se aplicará para a ordem dos destrutores. Por exemplo, durante a finalização de um programa uma variável estática pode ter sido destruída, mas código que ainda está rodando talvez em outra thread pode acabar tentando acessar essa variável. O o destrutor de uma variável string estática pode ser chamado antes do destrutor de outra variável que contém uma referência para essta string. Por essa razão, nós só permitimos que variáveis estáticas sejam para dados POD. Essa regra proíbe o uso de globais vector (use arrays C), ou string (use const char []). Se você precisa de precisa de uma variável estática ou global do tipo de uma classe, considere a possibilidade de inicializar um ponteiro (o qual nunca será liberado), a partir de main() ou de pthread_once(). Note que deve ser usado um ponteiro cru, não um smart pointer, pois o destrutor do smart pointer terá o problema da ordem de destrução que nós estamos tentando evitar. Classes Classes fazem parte da unidade fundamental de código em C++. Naturalmente, nós a usamos extensivamente. Essa seção lista o que você deve e o que você não deve fazer ao trabalhar com classes. Contrutores o que fazer neles Em geral, construtores devem apenas inicializar os valores das variáveis membros. Qualquer processo complexo para inicialização deve ser colocado em um método Init(). Definição O construtor pode ser usado para iniciar a classe e código relacionado a esse processo pode ser colocado no corpo do construtor. Pros Iniciar a classe no corpo do construtor é conveniente em questão de trabalho. Também, evita a preocupação sobre se a classe foi iniciada ou não. Os problemas gerados por se colocar tarefas no construtor são? Não um modo fácil para construtores indicarem erros, a menos que você use exceptions (o que não permitiremos). Se a tarefa falhar, nós teremos um objetos cujos código de inicialização falhou, e por isso seu estado será indeterminado. 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

14 Pesquisa e Desenvolvimento Tecnológico Se a tarefa chamar funções virtuais, essas chamadas não chegarão as implementações das subclasses (talvez no C++11 isso já está corrigido). Futuras modificações na sua classe podem gerar esse problema quase que imperceptivelmente, mesmo que a sua classe não esteja subclassificada mesmo, causando muita confusão. Se alguém criar uma variável global desse tipo (o que é proibido nesse guia), o código do construtor será chamado antes de main(), possivelmente quebrando algumas suposições implícitas código do construtor. Se o seu objeto requer inicialização não trivial, considere a possibilidade de usar um método init(). Em particular, construtores não devem chamar funções virtuais, não devem tentar emitir erros, acessar variáveis globais potencialmente não iniciadas e etc. Construtor Padrão Você deve definir um construtor padrão se a sua classe define variáveis membro e não tem outro construtor. Se não for esse o caso, o compilador fará isso para você, infelizmente. (Verificar mudanças no padrão C++11.) Definição O construtor padrão é chamado quando nós instanciamos um objeto de uma classe sem usar argumentos. Ele também sempre será chamado quando instanciamos objetos usando new[]. Prós Inicializar estruturas em default torna a depuração mais simples. Requer trabalho extra a criação de construtores padrão. Se a sua classe define variáveis membros e não possue outro construtor, você terá de definir um construtor padrão (que não recebe argumentos). Esse construtor deverá iniciar o objeto de um modo que o conteúdo dele seja consistente e válido. A razão para isso é que se você não tiver outro construtor e não definir um padrão, o compilador irá gerar um para você. Esse construtor gerado pelo compilador pode acabar não iniciando seu objeto do modo apropriado. Se a sua classe herda de uma classe existente, mas você não acrescenta novas variáveis membros, nesse caso não é necessária a criação de um construtor padrão. Construtor Explícito Use a palavra chave explicit para construtores com apenas um argumento. Definição Normalmente, se um construtor recebe apenas um argumento, ele pode ser usado como uma conversão. Por exemplo, se você definir Foo::Foo(string name) e então passar uma string para uma função que espera um Foo, o construtor será chamado para converter a string para um objeto Foo e passará o novo objeto automaticamente para você. Isso pode ser conveniente, mas é uma fonte de problemas quando as dados são convertidos e novos objetos são criados sem o seu conhecimento. Usar a palavra chave explicit impede que o construtor seja chamado implicitamente. Prós Evita conversões indesejadas. Nenhum.

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 15 Por padrão, todos os construtores com apenas um argumento devem ser explícitos. Sempre coloque explicit na frente do construtores com apenas um argumento na definição da classe: explicit Foo(string name); A excessão a regra são os construtores de cópia, os quais, em raros casos em que que serão permitidos, não devem ser explícitos. Também, outra excessão se no caso de classes que servem apenas como uma embalagem para outra classe. Tais exceções devem ser marcadas claramente com comentários. Construtor de Cópia Forneça um construtor de cópia e um operador de atribuição somente quando necessário. Caso contrário, os desabilite com DISALLOW_COPY_AND_ASSIGN. Definição O construtor de cópia e o operador de atribuição são usados para criar cópia de objetos. O construtor de cópia é chamado implicitamente pelo compilador em algumas situações, como por exemplo, ao passar objetos por valor. Prós Construtores de cópia tornam fácil a cópia de objetos. Containers STL necessitam que o conteúdo seja copiável e atribuível. Construtores de cópia são mais eficientes do que macetes do estilo CopiarDe() porque eles combinam a construção com a cópia, quando possível o compilador irá omití-los, e eles evitam alocação em heap. Cópia implícita em C++ é uma rica fonte de bugs e problemas de performance. Ela também reduz a legibilidade, porque se torna difícil detectar quais objetos estão sendo passados por valor, por geralmente se passa por referência, e portanto gera a dificuldade de detectar onde as mudanças a um objeto são refletidas. Poucas classe precisam ser copiáveis. A maioria não devem ter um construtor de cópia e um operador de atribuição. Em muitas situações, um ponteiro ou uma referência funcionarão tão bem quanto um valor copiado, mas com performance melhor. Por exemplo, você pode passar parâmetros de funções por referencia ou por ponteiro ao invés de por valor, e você pode armazenar ponteiros em vez de objetos dentro dos containers da STL. Se a sua classe precisa ser copiável, dê preferência ao uso de métodos como CopiarDe() ou Clone(), em lugar de um construtor de cópia, porque esses métodos não podem ser chamados de modo implícito. Se um método de cópia não for suficiente na sua situação (ex, por razões de desempenho, ou porque sua classe precisa ser armazenada por valor em um container), forneça tanto o construtor de cópia como o operador de atribuição. Se a sua classe não precisa de um construtor de cópia ou de um operador de atribuição, você deve desabilitá-los explicitamente. Para fazer isso, crie declarações vazias do construtor de cópia e do operador de atribuição na seção private: da sua classe, mas não forneça qualquer definição, para que qualquer tentativa de uso dessas funções resulte em um erro de link. Por conveniência, um macro DISALLOW_COPY_AND_ASSIGN pode ser usado: // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ void operator=(const TypeName&) O uso em uma classe é bem simples. class Foo { public: Foo(int f); ~Foo(); private: DISALLOW_COPY_AND_ASSIGN(Foo); ; 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

16 Pesquisa e Desenvolvimento Tecnológico Structs versus Classe Use uma estrutura apenas para passar objeto que transportam dados. Todo outro tipo de objeto é uma classe. As palavras chaves struct e class em se comportam praticamente de modo idêntico em C++. Nós definimos nosso próprio conceito semântico de cada uma delas, de modo que você saiba qual palavra-chave usar para um tipo de dado. Para objetos passivos que carregam dados, que talvez tenham constantes, mas que não necessitam de funcionalidades adicionais além de acessar e atribuir valores aos dados membros, structs devem ser usadas. Neste caso, o acesso e atribuição de valores em structs é feito diretamente sem a invocação de métodos. Métodos não devem fornecer comportamento, mas devem apenas ser usados para lidar com o dados membros, como por exemplo, construtores, destrutores, Inicializar(), Reset(), Validar(). Se mais funcionalidades forem necessárias, uma classe é mais apropriada. Na dúvida, use uma classe. Para consistência com a STL, você pode usar struct para functor e traits no lugas de classes. Classes também devem ser usados em casos onde ser requer interação com funções C onde só se aceita POD. Herança Composição sempre é mais apropriado que herança. Ao usar herança, torne-a publica. Definição Quando uma sub-classe herda de uma classe base, ela inclue todas as definições de todos os dados e operações que a classe base origem define. Na prática, herança é usado de dois principais modo em C++: herança de implementação, onde code real é herdado pela classe filha, e herança de interface, no qual apenas o nome dos métodos é herdado. Prós Herança de implementação reduz o tamanho do código fonte por reusar o código da classe base a medida que uma especialização do tipo é criada. Devido herança ser uma declaração em tempo de compilação, você e o compilador podem entender a operação e detectar erros. Herança de interface pode ser usada para garantir sintáticamente que uma classe fornece uma API em particular. De novo, o compilador pode detectar erros, nesse caso, quando uma classe não define um método necessário da API. No caso da herança de implementação, pode ser mais difícil entender o código porque o código implementando a sub-classe está espalhado entre a sub-classe e a classe base. A sub-classe não pode sobrecarregar classes que não são virtuais, o que impede mudar a implementação. A classe base pode definir também alguns dados membros que afetam o layout físico da classe base. Toda herança deve ser pública. Se você deseja fazer herança privada, você deve recorrer a composição do item na seção privada. Não faça uso excessivo de herança de implementação. Composição geralmente é mais apropriada. Tente restringir o uso de herança a casos específicos: Bar subclassifica Foo se pode ser dito de modo razoável que Bar é uma espécie de Foo. Declare seu destrutor como virtual quando necessário. Se a sua classe possuem métodos virtuais, seu destrutor deverá ser virtual. Limite o uso de protected a funções membros que podem precisar ser acessadas de subclasses. Note que dados membros devem ser privados.

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 17 Ao redefinir uma função virtual herdada, declare explicitamente a redefinição como virtual na classe derivada. Razão: se virtual for mitido, o leitor terá que checar todas os ancestrais da classe para verificar se a classe é virtual ou não. Herança Multipla Somente em casos bem raros herança múltipla será realmente útil. Nós permitiremos herança múltipla somento quando no máximo uma das classes bases possue implementação, sendo todas as outras classes bases apenas para herança de interface e marcadas com o sufixo Interface. Definição Herança múltipla permite que uma classe tenha mais que uma classe base. Nós fazemos distinção entre classes que são interfaces puras e aquelas que possuem uma implementação. Prós Herança múltipla de implementação lhe permite reusar mais código do herança única. Somente em casos bem raros herança múltipla é realmente necessária. Quando herança múltipla parece ser a melhor solução, você certamente poderá achar uma solução diferente, mais explícita e mais limpa. Herança múltipla só é permitida quando todas as superclasses, com uma possível concessão para a primeira, são interfaces puras. Para garantir que elas continuem como interfaces puras, elas devem terminar com o sufixo Interface. Interfaces Classes que satisfazem certas condições são permitidas terem o sufixo Interface, mas isso não é obrigatório. Definição Uma classe é uma interface pura se ela satisfaz os seguintes requerimentos: Ela só possuem métodos virtuais públicos puros ( = 0 ) e métodos estáticos (veja abaixo quanto ao destrutor). Ela não possue dados membros não-estáticos. Ela não precisa ter construtores. No entanto, se um construtor for provido, este não deve ter argumentos e deve ser protegido. Se ela for uma subclasse, ela deve ser derivada de classes que satisfaçam essas condições e que estão marcadas com o sufixo Interface. Uma interface não pode nunca ser instanciada diretamente por causa dos métodos virtuais puros que ela declara. Para ter certeza que todas as implementações da interface serão destruídas corretamente, a interface deve declara um destrutor virtual (como excessão a primeira regra, o destrutor não deve ser puro). Veja The C++ Programming Language, terceira edição de Stroustrup, seção 12.4. Pros Marcar uma classe com o sufixo Interface permite que outros saibam que eles não devem adicionar métodos implementados ou membros não-estáticos. Isso é especialmente importante quando se lida com herança múltipla. Além disso, o conceito de interfaces já é bem entendido por programadores Java e C#. O sufixo Interface enlarguece o nome da classe, o que torna mais difícil a leitura e a compreensão. Também, a posse da interface pode ser considerada um detalhe de implementação que não deveria ser exposta ao cliente. 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

18 Pesquisa e Desenvolvimento Tecnológico Uma classe pode terminar com Interface somente quando ela satisfaz o requerimentos mencionados. No entanto, o contrário não exigido: classes que satisfazem os requerimentos citados não são obrigadas a usar o sufixo. Sobrecarga de Operadores Não sobrecarregue operadores exceto em casos raros. Definição Uma classe pode definir que operadores como + e / operam na classe como se fossem parte do tipo. Prós Isso pode fazer o código parecer mais intuitivo porque uma classe se comportará de modo similar a um tipo built-in (como um int). Operadores de sobrecarga são nomes mais amigáveis para funções do que os menos atraentes, tais como Igual() ou Somar(). Para que algumas funções templates funcionem da maneira correta, você terá de definir operadores. Ao passo que sobrecarga de operadores pode tornar o código mais intuitivo, há também várias desvantagens: Ela pode nos levar a pensar erroneamente que operações caras são simples operações built-in. É bem mais difícil achar o ponto de chamada no caso de operadores sobrecarregados. Procurar por Igual() é muito mais fácil do que procurar por invocações de == que sejam relevantes. Alguns operadores funcionam também com ponteiros, tornando fácil a introduçãoo de bugs. Por exemplo, Foo + 4 pode fazer uma coisa enquanto &Foo + 4 fará algo totalmente diferente. O compilador não reclama de ambos os casos, tornando difícil a depuração. Sobrecarga também tem efeitos colaterais surpreendentes. Por exemplo, se uma classe sobrecarregar o operador referencial operator&, essa classe não poderá ter uma forward declaration de modo seguro. Em geral, não sobrecarregue operadores. O operador de atribuição (operator=), em particular, é insidioso e deve ser evitado. Você pode definir funções como Igual() e CopiarDe() se você precisar deles. De modo similar, evite o perigoso operator& a qualquer custo, se houver qualquer possibilidade que essa classe tenha que ser usada com forward declarations. Entretanto, há casos raros onde você precisa sobrecarregar um operador para interagir com as classes C++ standart (como no caso do operator<<(ostream&, const T&) para fazer logging). Esses casos aceitáveis, mas devem ser evitados sempre que possível. Em partícula, não sobrecarregue o operator== ou operator< só para que a sua classe possa ser usada como uma chave em um container STL. Ao invés disso, você deve criar functors de igualdade e de comparação ao declarar um container. Alguns dos algorítimos da SLT exigem que você sobrecarregue o operator==, e você pode isso nesses casos, desde que você documente porque. Veja também os tópicos Construtor de Cópia e Sobrecarga de Funções. Controle de Acesso Use a ordem de declaração especificada dentro de uma classe: public: antes de private:, métodos antes de dados membros (variáveis), etc. A definição da sua classe deve começao com a seção public:, seguida pela seção protected: e então pela seção private:. Se qualquer uma dessas seções estiverem vazias, suprima-ás. Dentro de cada seção, a declaração deve ser na seguinte ordem:

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 19 Typedefs e Enums Contantes (dados membros static const) Construtores Destrutores Métodos, incluindo métodos estáticos Dados membros (exceto dados membros static const) Declarações Friend dvem sempre estar na seção privada, e o macro DISALLOW_COPY_AND_CONSTRUCTION deve ficar no fim da seção privada. Ele deve ser a ultima coisa na classe. A definição dos métodos no arquivo.cpp deve estar na mesma ordem que ocorreu a declaração, tanto quanto possível. Não coloque a definição de métodos extensos inline dentro da definição da classe. Normalmente, apenas métodos triviais ou críticos para performance, bem curtos, podem ser definido inline. Veja Funções Inline para mais detalhes. Escreva Funções Curtas Prefira funções pequenas e consisas. Nós reconhecemos que funções longas algumas vezes são apropriadas, de modo que nenhum limite específico é imposto em funções. Se uma função requer 40 linhas ou mais, considere a possibilidade de fragmentá-la sem causar dano a estrutura do programa. Mesmo que a sua função longa funcione perfeitamente hoje, alguém modificando ela alguns meses mais tarde pode criar um novo comportamento. Isso pode resultar em bugs difíceis de detectar. Manter suas funções curtas e simples torna mais fácil o trabalho que outras pessoas terão em ler usa função e modificar seu código. Você talvez encontre funções longas e complicadas ao trabalhar com algum código. Não fique intimidado em modificar o código existente: se trabalhar com essa função parecer difícil, você perceber que erros são difíceis de depurar, ou se você deseja usar um pedaço dessa função em vários contextos diferentes, considere a possibilidade de fragmentar essa função em pedaços menores e mais fáceis de gerenciar. Outros Recursos C++ Delinearemos agora como lidar com recursos mais básico não diretamente ligados a OO em C++. Argumentos Referências Em C, se uma função precisa modificar uma variável, o programador precisa usar um ponteiro (ex, int foo(int *pval) ). Em C++ a função pode alternativamente declarar um parâmetro referencia: int foo(int &val). Prós Definir um parâmetro como referência evita código estranho como (*pval)++. São necessárias em construtores de cópia. Torna evidente, diferente do que acontece com um ponteiro, que NULL não é um valor válido. Referências podem ser confusas por que elas usam a sintaxe de valor mas possuem a semântica de ponteiros. Dentro da lista de parâmetros de uma função, todas as referências devem ser const: void Foo(const string &in, string *out); 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

20 Pesquisa e Desenvolvimento Tecnológico De fato, o estilo deve ser fortamente assegurado que argumentos de entrada sejam ou valores ou referências const enquanto os argumentos de saída são ponteiros. Parâmetros de entrada podem ser ponteiro const,mas não permitiremos o uso de referências não-const. No entanto, há alguns lugares onde o uso de const T* é preferível em lugar de const T& para parâmetros de entrada. Por exemplo: Você deseja manter aberta a opção de passar NULL. A função salva um ponteiro ou uma referência em relação a entrada. Lembre-se que a maior parte do tempo, parâmetros de entrada serão definidos como const T&. O uso de const T* indica para o leitor que a entrada é tratada diferente de algum modo. Assim, caso você use const T* ao invés de const T&, faça isso por alguma razão concreta. Não seguir isso confundirá o leitor que tentará procura por explicações que não existem. Sobrecarga de Funções Use funções sobrecarregadas (incluindo construtores) somente se o leitor no local da chamada pode ter uma boa idéia do que está acontecendo sem ter que descobrir primeiro qual sobrecarga está sendo chamada. Definição Você pode escrever uma função que recebe uma const string& e sobrecarrega-la com outra que recebe const char*. class MyClass { public: void Analyze(const string &text); void Analyze(const char *text, size_t textlen); ; Prós Sobrecarga pode tornar o código mais intuitivo por permitir que uma função com nome idêntico a outra tenha argumentos diferentes. Sobrecarga pode ser necessária para código em Templates e poderá ser conveniente para visitantes. Se uma função é sobrecarregada apenas pelos tipos de argumentos, um leitor terá que entender as complexas regras de C++ de identificão para entender o que está acontecendo. Também, muitas pessoas ficam confusas com a semântica da herança se uma classe derivada sobrecarrega apenas algumas variantes de uma função. Se você deseja sobrecarregar uma função, considere qualificar o nome com alguma informação sobre os argumentos, como por exemplo, AppendString(), AppendInt() ao invés de apenas Append(). Algumentos Default Não é permitido o uso de argumentos default, exceto em algumas situações atípicas explicadas adiante. Prós Frequentemente você tem uma função que usa vários valores padrões, mas em algumas situações você deja sobrecarrega os valores default. Parâmetros default possibilitam um modo fácil de fazer isso sem ter que definir muitas funções para as raras exceções. As pessoas geralmente aprendem a usar uma API por olha em código existente que usa essas APIs. Parâmetros default são mais difíceis de manter porque copiar-e-colar do código anterior pode não revelar todos os parâmetros. Copiar-e-colar segmentos do código pode causar problemas maiores quando os argumentos padrões não são apropriados para o novo código.

Pesquisa e Desenvolvimento Tecnológico - Guia Para Estilo de Código C++ 21 Exceto no caso descrito abaixo, nós exigimos que todos os argumentos sejam especificados explicitamente, para forçar os programadores a considerar a API e os valores que eles estão passando para cada argumento de silenciosamente aceitar defaults que eles não estão cientes. Uma excessão é quando argumentos default são usados para simular lista de argumentos de tamanho variável. // Suporta até quatro algumentos por usar um AlphaNum vazio. string StrCat(const AlphaNum &a, const AlphaNum &b = gemptyalphanum, const AlphaNum &c = gemptyalphanum, const AlphaNum &d = gemptyalphanum); Arrays de Tamanho variável e alloca() Nós não permitimos o uso de arrays de tamanho variável ou alloca(). Prós Arrays de tamanho variável possuem uma sintaxe natural. Tanto arrays de tamanho variável quanto alloca() são bem aficiêntes. Arrays de tamanho variável e alloca() não fazem parte do padrão C++. Mais importante, eles alocam uma quantidade de espaço no stack que depende do tipo sendo alocado que pode criar bugs de overflow difíceis de achar. Funciona uma maravilha no meu computador, mas na produção misteriosamente morre. Use em lugar disso um alocador seguro como std::array/std::unique_prt/scoped_array. Friends Nós permitimos o uso de classes e funções friend, dentre de alguns limites. Friends normalmente devem ser definidas no mesmo arquivo, para que o leitor não tenha que procurar em outro arquivo para encontrar usos dos dados privados de uma classe. Um uso comum de friend é fazer com que a classe FooBuilder seja amiga da classe Foo de modo que ela possa construir o estado interno de Foo corretamente, sem expor esse estado externamente. Em alguns casos pode ser útil torna a classe de unit teste amiga da classe que está sendo testada. Friends ampliam, mas não quebram, o limite encapsulamento de uma classe. Em alguns casos isso é melhor do que tornar um membro público quando você apenas deseja concender acesso a uma outra classe. Entretanto, a maioria das classes devem interagir com outras classes unicamente pelas interfaces públicas. Exceções Nós não usamos exceções. Prós Exceções permitem que níveis mais altos de uma aplicação decidam como lidar com falhas críticas que ocorrem em funções aninhadas em níveis mais profundos, sem o uso obscuro e propenso a erro da transmissão de códigos de erros. Exceções são usadas pelas linguagens mais modernas. Usá-las em C++ tornaria o código mais consistente com linguagens como Python, Java, e o C++ que outros já estão familiarizados. Algumas bibliotecas de terceiros em C++ usam exceptions e desliga-las torna complicada a integração com tais bibliotecas. 2011Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.