learnxinyminutes-docs/pt-br/c++.md
2024-12-08 20:37:52 -07:00

18 KiB

language filename contributors translators
C++ learncpp-pt.cpp
Steven Basart
http://github.com/xksteven
Matt Kline
https://github.com/mrkline
Miguel Araújo
https://github.com/miguelarauj1o

C++ é uma linguagem de programação de sistemas que, de acordo com seu inventor Bjarne Stroustrup, foi concebida para

  • ser um "C melhor"
  • suportar abstração de dados
  • suportar programação orientada a objetos
  • suportar programação genérica

Embora sua sintaxe possa ser mais difícil ou complexa do que as linguagens mais recentes, C++ é amplamente utilizada porque compila para instruções nativas que podem ser executadas diretamente pelo processador e oferece um controle rígido sobre o hardware (como C), enquanto oferece recursos de alto nível, como os genéricos, exceções e classes. Esta combinação de velocidade e funcionalidade faz C++ uma das linguagens de programação mais utilizadas.

//////////////////
// Comparação com C
//////////////////

// C ++ é quase um super conjunto de C e compartilha sua sintaxe básica para
// declarações de variáveis, tipos primitivos, e funções. No entanto, C++ varia
// em algumas das seguintes maneiras:

// A função main() em C++ deve retornar um int, embora void main() é aceita
// pela maioria dos compiladores (gcc, bumbum, etc.)
// Este valor serve como o status de saída do programa.
// Veja http://en.wikipedia.org/wiki/Exit_status para mais informações.

int main(int argc, char** argv)
{
    // Argumentos de linha de comando são passados para argc e argv da mesma
    // forma que eles estão em C.
    // argc indica o número de argumentos,
    // e argv é um array de strings, feito C (char*) representando os argumentos
    // O primeiro argumento é o nome pelo qual o programa foi chamado.
    // argc e argv pode ser omitido se você não se importa com argumentos,
    // dando a assinatura da função de int main()

    // Uma saída de status de 0 indica sucesso.
    return 0;
}

// Em C++, caracteres literais são um byte.
sizeof('c') == 1

// Em C, caracteres literais são do mesmo tamanho que ints.
sizeof('c') == sizeof(10)

// C++ tem prototipagem estrita
void func(); // função que não aceita argumentos

// Em C
void func(); // função que pode aceitar qualquer número de argumentos

// Use nullptr em vez de NULL em C++
int* ip = nullptr;

// Cabeçalhos padrão C estão disponíveis em C++,
// mas são prefixados com "c" e não têm sufixo .h

#include <cstdio>

int main()
{
    printf("Hello, world!\n");
    return 0;
}

///////////////////////
// Sobrecarga de função
///////////////////////

// C++ suporta sobrecarga de função
// desde que cada função tenha parâmetros diferentes.

void print(char const* myString)
{
    printf("String %s\n", myString);
}

void print(int myInt)
{
    printf("My int is %d", myInt);
}

int main()
{
    print("Hello"); // Funciona para void print(const char*)
    print(15); // Funciona para void print(int)
}

/////////////////////////////
// Parâmetros padrão de função
/////////////////////////////

// Você pode fornecer argumentos padrões para uma função se eles não são
// fornecidos pelo chamador.

void doSomethingWithInts(int a = 1, int b = 4)
{
    // Faça alguma coisa com os ints aqui
}

int main()
{
    doSomethingWithInts();      // a = 1,  b = 4
    doSomethingWithInts(20);    // a = 20, b = 4
    doSomethingWithInts(20, 5); // a = 20, b = 5
}

// Argumentos padrões devem estar no final da lista de argumentos.

void invalidDeclaration(int a = 1, int b) // Erro!
{
}


/////////////
// Namespaces (nome de espaços)
/////////////

// Namespaces fornecem escopos distintos para variável, função e outras
// declarações. Namespaces podem estar aninhados.

namespace First {
    namespace Nested {
        void foo()
        {
            printf("This is First::Nested::foo\n");
        }
    } // Fim do namespace aninhado
} // Fim do namespace First

namespace Second {
    void foo()
    {
        printf("This is Second::foo\n")
    }
}

void foo()
{
    printf("This is global foo\n");
}

int main()
{
    // Assuma que tudo é do namespace "Second" a menos que especificado de
    // outra forma.
    using namespace Second;

    foo(); // imprime "This is Second::foo"
    First::Nested::foo(); // imprime "This is First::Nested::foo"
    ::foo(); // imprime "This is global foo"
}

///////////////
// Entrada/Saída
///////////////

// C ++ usa a entrada e saída de fluxos (streams)
// cin, cout, and cerr representa stdin, stdout, and stderr.
// << É o operador de inserção e >> é o operador de extração.

#include <iostream> // Inclusão para o I/O streams

using namespace std; // Streams estão no namespace std (biblioteca padrão)

int main()
{
   int myInt;

   // Imprime na saída padrão (ou terminal/tela)
   cout << "Enter your favorite number:\n";
   // Pega a entrada
   cin >> myInt;

   // cout também pode ser formatado
   cout << "Your favorite number is " << myInt << "\n";
   // imprime "Your favorite number is <myInt>"

    cerr << "Usado para mensagens de erro";
}

//////////
// Strings
//////////

// Strings em C++ são objetos e têm muitas funções de membro
#include <string>

using namespace std; // Strings também estão no namespace std (bib. padrão)

string myString = "Hello";
string myOtherString = " World";

// + é usado para concatenação.
cout << myString + myOtherString; // "Hello World"

cout << myString + " You"; // "Hello You"

// Em C++, strings são mutáveis e têm valores semânticos.
myString.append(" Dog");
cout << myString; // "Hello Dog"


/////////////
// Referência
/////////////

// Além de indicadores como os de C, C++ têm _referências_. Esses são tipos de
// ponteiro que não pode ser reatribuída uma vez definidos e não pode ser nulo.
// Eles também têm a mesma sintaxe que a própria variável: Não * é necessário
// para _dereferencing_ e & (endereço de) não é usado para atribuição.

using namespace std;

string foo = "I am foo";
string bar = "I am bar";


string& fooRef = foo; // Isso cria uma referência para foo.
fooRef += ". Hi!"; // Modifica foo através da referência
cout << fooRef; // Imprime "I am foo. Hi!"

// Não realocar "fooRef". Este é o mesmo que "foo = bar", e foo == "I am bar"
// depois desta linha.

fooRef = bar;

const string& barRef = bar; // Cria uma referência const para bar.
// Como C, valores const (e ponteiros e referências) não podem ser modificado.
barRef += ". Hi!"; // Erro, referência const não pode ser modificada.

//////////////////////////////////////////
// Classes e programação orientada a objeto
//////////////////////////////////////////

// Primeiro exemplo de classes
#include <iostream>

// Declara a classe.
// As classes são geralmente declarado no cabeçalho arquivos (.h ou .hpp).
class Dog {
    // Variáveis de membro e funções são privadas por padrão.
    std::string name;
    int weight;

// Todos os membros a seguir este são públicos até que "private:" ou
// "protected:" é encontrado.
public:

    // Construtor padrão
    Dog();

    // Declarações de função Membro (implementações a seguir)
    // Note que usamos std :: string aqui em vez de colocar
    // using namespace std;
    // acima.
    // Nunca coloque uma declaração "using namespace" em um cabeçalho.
    void setName(const std::string& dogsName);

    void setWeight(int dogsWeight);

    // Funções que não modificam o estado do objeto devem ser marcadas como
    // const. Isso permite que você chamá-los se for dada uma referência const
    // para o objeto. Além disso, observe as funções devem ser explicitamente
    // declarados como _virtual_, a fim de ser substituídas em classes
    // derivadas. As funções não são virtuais por padrão por razões de
    // performance.

    virtual void print() const;

    // As funções também podem ser definidas no interior do corpo da classe.
    // Funções definidas como tal são automaticamente embutidas.
    void bark() const { std::cout << name << " barks!\n" }

    // Junto com os construtores, C++ fornece destruidores.
    // Estes são chamados quando um objeto é excluído ou fica fora do escopo.
    // Isto permite paradigmas poderosos, como RAII
    // (veja abaixo)
    // Destruidores devem ser virtual para permitir que as classes de ser
    // derivada desta.
    virtual ~Dog();

}; // Um ponto e vírgula deve seguir a definição de classe.

// Funções membro da classe geralmente são implementados em arquivos .cpp.
void Dog::Dog()
{
    std::cout << "A dog has been constructed\n";
}

// Objetos (como strings) devem ser passados por referência
// se você pretende modificá-los, ou com const caso contrário.
void Dog::setName(const std::string& dogsName)
{
    name = dogsName;
}

void Dog::setWeight(int dogsWeight)
{
    weight = dogsWeight;
}

// Observe que "virtual" só é necessária na declaração, não a definição.
void Dog::print() const
{
    std::cout << "Dog is " << name << " and weighs " << weight << "kg\n";
}

void Dog::~Dog()
{
    std::cout << "Goodbye " << name << "\n";
}

int main() {
    Dog myDog; // imprime "A dog has been constructed"
    myDog.setName("Barkley");
    myDog.setWeight(10);
    myDog.printDog(); // imprime "Dog is Barkley and weighs 10 kg"
    return 0;
} // imprime "Goodbye Barkley"

// herança:

// Essa classe herda tudo público e protegido da classe Dog
class OwnedDog : public Dog {

    void setOwner(const std::string& dogsOwner)

    // Substituir o comportamento da função de impressão de todas OwnedDogs.
    // Ver http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping
    // Para uma introdução mais geral, se você não estiver familiarizado com o
    // polimorfismo subtipo. A palavra-chave override é opcional, mas torna-se
    // na verdade você está substituindo o método em uma classe base.
    void print() const override;

private:
    std::string owner;
};

// Enquanto isso, no arquivo .cpp correspondente:

void OwnedDog::setOwner(const std::string& dogsOwner)
{
    owner = dogsOwner;
}

void OwnedDog::print() const
{
    Dog::print(); // Chame a função de impressão na classe Dog base de
    std::cout << "Dog is owned by " << owner << "\n";
    // Imprime "Dog is <name> and weights <weight>"
    //        "Dog is owned by <owner>"
}

//////////////////////////////////////////
// Inicialização e Sobrecarga de Operadores
//////////////////////////////////////////

// Em C ++, você pode sobrecarregar o comportamento dos operadores, tais como
// +, -, *, /, etc. Isto é feito através da definição de uma função que é
// chamado sempre que o operador é usado.

#include <iostream>
using namespace std;

class Point {
public:
    // Variáveis membro pode ser dado valores padrão desta maneira.
    double x = 0;
    double y = 0;

    // Define um construtor padrão que não faz nada
    // mas inicializar o Point para o valor padrão (0, 0)
    Point() { };

    // A sintaxe a seguir é conhecido como uma lista de inicialização
    // e é a maneira correta de inicializar os valores de membro de classe
    Point (double a, double b) :
        x(a),
        y(b)
    { /* Não fazer nada, exceto inicializar os valores */ }

    // Sobrecarrega o operador +.
    Point operator+(const Point& rhs) const;

    // Sobrecarregar o operador +=.
    Point& operator+=(const Point& rhs);

    // Ele também faria sentido para adicionar os operadores - e -=,
    // mas vamos pular para sermos breves.
};

Point Point::operator+(const Point& rhs) const
{
    // Criar um novo ponto que é a soma de um e rhs.
    return Point(x + rhs.x, y + rhs.y);
}

Point& Point::operator+=(const Point& rhs)
{
    x += rhs.x;
    y += rhs.y;
    return *this;
}

int main () {
    Point up (0,1);
    Point right (1,0);
    // Isto chama que o operador ponto +
    // Ressalte-se a chamadas (função)+ com direito como seu parâmetro...
    Point result = up + right;
    // Imprime "Result is upright (1,1)"
    cout << "Result is upright (" << result.x << ',' << result.y << ")\n";
    return 0;
}

/////////////////////////
// Tratamento de Exceções
/////////////////////////

// A biblioteca padrão fornece alguns tipos de exceção
// (see http://en.cppreference.com/w/cpp/error/exception)
// mas qualquer tipo pode ser jogado como uma exceção
#include <exception>

// Todas as exceções lançadas dentro do bloco try pode ser capturado por
// manipuladores de captura subseqüentes
try {
    // Não aloca exceções no heap usando _new_.
    throw std::exception("A problem occurred");
}
// Capturar exceções por referência const se eles são objetos
catch (const std::exception& ex)
{
  std::cout << ex.what();
// Captura qualquer exceção não capturada pelos blocos _catch_ anteriores
} catch (...)
{
    std::cout << "Exceção desconhecida encontrada";
    throw; // Re-lança a exceção
}

///////
// RAII
///////

// RAII significa alocação de recursos é de inicialização.
// Muitas vezes, é considerado o paradigma mais poderoso em C++, e é o
// conceito simples que um construtor para um objeto adquire recursos daquele
// objeto e o destruidor liberá-los.

// Para entender como isso é útil,
// Considere uma função que usa um identificador de arquivo C:
void doSomethingWithAFile(const char* filename)
{
    // Para começar, assuma que nada pode falhar.

    FILE* fh = fopen(filename, "r"); // Abra o arquivo em modo de leitura.

    doSomethingWithTheFile(fh);
    doSomethingElseWithIt(fh);

    fclose(fh); // Feche o arquivo.
}

// Infelizmente, as coisas são levemente complicadas para tratamento de erros.
// Suponha que fopen pode falhar, e que doSomethingWithTheFile e
// doSomethingElseWithIt retornam códigos de erro se eles falharem. (As
// exceções são a forma preferida de lidar com o fracasso, mas alguns
// programadores, especialmente aqueles com um conhecimento em C, discordam
// sobre a utilidade de exceções). Agora temos que verificar cada chamada para
// o fracasso e fechar o identificador de arquivo se ocorreu um problema.

bool doSomethingWithAFile(const char* filename)
{
    FILE* fh = fopen(filename, "r"); // Abra o arquivo em modo de leitura
    if (fh == nullptr) // O ponteiro retornado é nulo em caso de falha.
        return false; // Relate o fracasso para o chamador.

    // Suponha cada função retorne false, se falhar
    if (!doSomethingWithTheFile(fh)) {
        fclose(fh); // Feche o identificador de arquivo para que ele não vaze.
        return false; // Propague o erro.
    }
    if (!doSomethingElseWithIt(fh)) {
        fclose(fh); // Feche o identificador de arquivo para que ele não vaze.
        return false; // Propague o erro.
    }

    fclose(fh); // Feche o identificador de arquivo para que ele não vaze.
    return true; // Indica sucesso
}

// Programadores C frequentemente limpam isso um pouco usando Goto:
bool doSomethingWithAFile(const char* filename)
{
    FILE* fh = fopen(filename, "r");
    if (fh == nullptr)
        return false;

    if (!doSomethingWithTheFile(fh))
        goto failure;

    if (!doSomethingElseWithIt(fh))
        goto failure;

    fclose(fh); // Close the file
    return true; // Indica sucesso

failure:
    fclose(fh);
    return false; // Propague o erro.
}

// Se as funções indicam erros usando exceções,
// as coisas são um pouco mais limpo, mas ainda abaixo do ideal.
void doSomethingWithAFile(const char* filename)
{
    FILE* fh = fopen(filename, "r"); // Abra o arquivo em modo de leitura.
    if (fh == nullptr)
        throw std::exception("Não pode abrir o arquivo.");

    try {
        doSomethingWithTheFile(fh);
        doSomethingElseWithIt(fh);
    }
    catch (...) {
        fclose(fh); // Certifique-se de fechar o arquivo se ocorrer um erro.
        throw; // Em seguida, re-lance a exceção.
    }

    fclose(fh); // Feche o arquivo
    // Tudo ocorreu com sucesso!
}

// Compare isso com o uso de C++ classe fluxo de arquivo (fstream) fstream usa
// seu destruidor para fechar o arquivo. Lembre-se de cima que destruidores são
// automaticamente chamado sempre que um objeto cai fora do âmbito.
void doSomethingWithAFile(const std::string& filename)
{
    // ifstream é curto para o fluxo de arquivo de entrada
    std::ifstream fh(filename); // Abra o arquivo

    // faça alguma coisa com o arquivo
    doSomethingWithTheFile(fh);
    doSomethingElseWithIt(fh);

} // O arquivo é automaticamente fechado aqui pelo destructor

// Isto tem _grandes_ vantagens:
// 1. Não importa o que aconteça,
//    o recurso (neste caso, o identificador de ficheiro) será limpo.
//    Depois de escrever o destruidor corretamente,
//    É _impossível_ esquecer de fechar e vazar o recurso
// 2. Nota-se que o código é muito mais limpo.
//    As alças destructor fecham o arquivo por trás das cenas
//    sem que você precise se preocupar com isso.
// 3. O código é seguro de exceção.
//    Uma exceção pode ser lançada em qualquer lugar na função e a limpeza
//    ainda irá ocorrer.

// Todos códigos C++ usam RAII extensivamente para todos os recursos.
// Outros exemplos incluem
// - Memória usa unique_ptr e shared_ptr
// - Contentores - a lista da biblioteca ligada padrão,
//   vetor (i.e. array de autodimensionamento), mapas hash, e assim por diante
//   tudo é automaticamente destruído quando eles saem de escopo
// - Mutex usa lock_guard e unique_lock


/////////////////////
// Templates
/////////////////////

// Templates em C++ são utilizados para programação genérica, ou seja,
// utilizar um tipo de dado genérico onde possa suportar qualquer entrada.
// Por exemplo, invés de criar uma função que apenas some inteiros, você
// poderá fazer uma função que soma double, float e inteiros em uma única
// definição para reutilizar código.

// Definimos um função que utiliza um "typename"
template<class T>
T soma(T a, T b) {
  return A + B;
}

// E agora para executá-la
int i=5, j=6, k;
double f=2.0, g=0.5, h;
k=sum<int>(i,j);
h=sum<double>(f,g);

// Deste modo, não precisamos fazer overload nas funções! (:

Leitura Adicional:

  • Uma referência atualizada da linguagem pode ser encontrada em CPP Reference.
  • Uma fonte adicional pode ser encontrada em CPlusPlus.
  • Um tutorial cobrindo o básico da linguagem e configurando o ambiente de codificação está disponível em TheChernoProject - C ++.