C++: Noções Básicas de Herança

Última atualização: 2026-08-26

Imagine que você escreveu classes Student e Teacher, e percebeu que ambas têm nome e idade, mas estudantes têm matrícula e professores têm número de funcionário.

Você pode reutilizar o código da classe Person? Herança faz exatamente isso — criando um relacionamento "pai-filho" entre classes.


1. O que é Herança?

(1) 1.1 Herança no Dia a Dia

Exemplo do Dia a Dia Equivalente no Programa
Um filho herda características dos pais (cor dos olhos, altura, etc.) Uma classe derivada herda membros de sua classe base
Um filho pode ter suas próprias características (como talentos especiais) Uma classe derivada pode adicionar novos membros

A essência da herança: Criar novas classes estendendo classes existentes.

(2) 1.2 Por que Precisamos de Herança?

Sem herança (código duplicado):

▶ Exemplo 2: Exemplo de Código (Dificuldade ⭐)

CPP
#include <iostream>
#include <string>

// Classe Student
class Student {
 std::string name;
 int age;
 std::string studentId;
};

// Classe Teacher
class Teacher {
 std::string name; // ❌ Duplicado
 int age; // ❌ Duplicado
 std::string teacherId;
};
▶ Experimente

Saída:

TEXT 📖 Somente leitura
(program output)

Com herança (reutilização de código):

CPP
#include <iostream>
#include <string>

// Classe base (classe pai)
class Person {
public:
 std::string name;
 int age;
};

// Classe derivada (classe filho)
class Student : public Person {
public:
 std::string studentId; // Novo membro
};

class Teacher : public Person {
public:
 std::string teacherId; // Novo membro
};


2. Sintaxe Básica de Herança

(1) 2.1 Declarando uma Classe Derivada

Sintaxe:

TEXT 📖 Somente leitura
class DerivedClassName : inheritanceMode BaseClassName {
 // novos membros
};

Exemplo:

CPP
#include <iostream>
#include <string>

class Person {
public:
 std::string name;
 int age;
};

// Student herda de Person
class Student : public Person {
public:
 std::string studentId;
};

int main() {
 Student s1;
 s1.name = "Alice"; // ✅ name herdado
 s1.age = 20; // ✅ age herdado
 s1.studentId = "2024001"; // Membro próprio
 
 std::cout << "Nome: " << s1.name << std::endl;
 std::cout << "Idade: " << s1.age << std::endl;
 std::cout << "Matrícula: " << s1.studentId << std::endl;
 
 return 0;
}


3. Modos de Herança (Controle de Acesso)

(1) 3.1 Três Modos de Herança

Membro da Classe Base \ Modo de Herança Herança public Herança protected Herança private
membros public public (inalterado) protected private
membros protected protected protected private
membros private Não acessível Não acessível Não acessível

💡 Ponto Importante: O modo de herança mais usado é a herança public.

(2) 3.2 Herança public (Recomendada)

CPP
#include <iostream>
#include <string>

class Person {
private:
 std::string id; // Membro privado: não acessível pela classe derivada
 
protected:
 std::string address; // Membro protegido: acessível pela classe derivada
 
public:
 std::string name; // Membro público: acessível por todos
 
 void introduce() {
 std::cout << "Meu nome é " << name << std::endl;
 }
};

class Student : public Person {
public:
 void setAddress(const std::string& addr) {
 address = addr; // ✅ Pode acessar membro protegido
 // id = "123"; // ❌ Não pode acessar membro privado
 }
};

int main() {
 Student s1;
 s1.name = "Alice"; // ✅ Acessível
 // s1.address = "Wuhan"; // ❌ Não acessível (protegido)
 
 return 0;
}


4. Construtores e Herança

(1) 4.1 Ordem de Chamada do Construtor da Classe Derivada

Regra: O construtor da classe base é chamado primeiro, depois o construtor da classe derivada.

CPP
#include <iostream>
#include <string>

class Person {
public:
 Person() {
 std::cout << "Construtor Person" << std::endl;
 }
};

class Student : public Person {
public:
 Student() {
 std::cout << "Construtor Student" << std::endl;
 }
};

int main() {
 Student s1;
 return 0;
}

💡 Ponto Importante: A ordem de chamada do destrutor é invertida — o destrutor da classe derivada é chamado primeiro, depois o da classe base.



5. Prática: Sistema Simples de Gerenciamento de Estudantes (Versão com Herança)

▶ Exemplo 1: Implementação Usando Herança (Dificuldade ⭐⭐)

CPP
#include <iostream>
#include <string>

// Classe base
class Person {
protected:
 std::string name;
 int age;
 
public:
 Person(const std::string& n, int a) : name(n), age(a) {}
 
 void introduce() {
 std::cout << "Nome: " << name << ",Idade: " << age << std::endl;
 }
};

// Classe derivada: Student
class Student : public Person {
private:
 std::string studentId;
 double score;
 
public:
 Student(const std::string& n, int a, const std::string& id, double s)
 : Person(n, a), studentId(id), score(s) {}
 
 void introduce() {
 Person::introduce(); // Chamar introduce da classe base
 std::cout << "Matrícula: " << studentId << ",Nota: " << score << std::endl;
 }
};

int main() {
 Student s1("Alice", 20, "2024001", 92.5);
 s1.introduce();
 
 return 0;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Nome: Alice,Idade: 20
Matrícula: 2024001,Nota: 92.5

❓ Perguntas Frequentes

P: Por que uma classe derivada não pode acessar os membros private da classe base? R: Isso é um requisito de encapsulamento — a classe base pode ocultar detalhes de implementação e expor apenas a interface.

Se uma classe derivada precisa acessar membros da classe base, declare-os como protected.

P: Quais são os modos de herança? Qual devo usar? R: > - Herança public: mais usada, preserva a interface da classe base > - Herança protected: raramente usada > - Herança private: raramente usada

Recomendação: Sempre use herança public.

P: Construtores da classe base podem ser herdados? R: Não. Classes derivadas devem definir seus próprios construtores e chamar o construtor da classe base na lista de inicialização.

CPP
Student(const std::string& n, int a) : Person(n, a) {} // Correto

▶ Exemplo 3: Construtor de Classe Derivada (Dificuldade ⭐)

CPP
#include <iostream>
#include <string>

class Animal {
protected:
    std::string name;
public:
    Animal(std::string n) : name(n) {}
    void speak() { std::cout << name << "faz um som" << std::endl; }
};

class Dog : public Animal {
public:
    Dog(std::string n) : Animal(n) {}
    void speak() { std::cout << name << "late" << std::endl; }
};

int main() {
    Dog dog("Wangcai");
    dog.speak();

    return 0;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Wangcailate
💡 Dica: Construtores de classes derivadas precisam chamar o construtor da classe base para inicializar os membros da classe base. Classes derivadas podem sobrescrever funções membro da classe base.


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Defina uma classe base Animal com um membro name. Faça as classes Dog e Cat herdarem dela.

  2. Intermediário (Dificuldade ⭐⭐): Estenda o programa acima adicionando uma função virtual void speak() a Animal (você aprenderá sobre funções virtuais depois), e faça Dog e Cat sobrescrevê-la.

  3. Desafio (Dificuldade ⭐⭐⭐): Projete uma hierarquia de classes para um sistema de gerenciamento de biblioteca:

  4. Person (nome, idade)

  5. Student herda de Person (matrícula, número de livros emprestados)

  6. Teacher herda de Person (número de funcionário, número de livros emprestados)

  7. Implemente funcionalidade de empréstimo e devolução.

  8. Herança: classes derivadas têm todos os membros da classe base

  1. Construtores de classes derivadas chamam construtores da classe base
  2. Relacionamento é-um: uma classe derivada é um tipo de classe base

6. 🚀 Próximos Passos

Agora que você aprendeu o básico de herança, vamos avançar para Polimorfismo (Aula 32) — permitindo que ponteiros da classe base chamem funções da classe derivada para "uma interface, múltiplas implementações"!

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%