O principal característica da OOP é o incentivo à reutilização de código através de herança. Uma nova classe é feita a partir de uma já existente, que é chamada de classe base. A classe derivada usa os membros da classe base, mas também pode modificar e complementá-los.

Muitos tipos são variações de tipos já existentes. É muitas vezes tedioso desenvolver um novo código para cada um deles. Além disso, um novo código implica em novos erros. A classe derivada herda a descrição da classe base, assim qualquer re-desenvolvimento e re-teste de código é desnecessário. As relações de herança são hierárquicas.

Hierarquia é um método que permite copiar os elementos em toda a sua diversidade e complexidade. Ela introduz a classificação de objetos. Por exemplo, a tabela periódica de elementos tem gases. Eles possuem propriedades inerentes a todos os elementos periódicos.

Gases inertes constituem a próxima importante subclasse. A hierarquia é que o gás inerte, como árgon, é um gás, e um gás, por sua vez, é parte do sistema. Tal hierarquia permite interpretar o comportamento dos gases inertes com facilidade. Sabemos que seus átomos contêm prótons e elétrons, o que é verdade para todos os outros elementos.

Sabemos que eles estão no estado gasoso à temperatura ambiente, como todos os gases. Sabemos que nenhum gás da subclasse de gases inertes entra usualmente em reações químicas com outros elementos, e isso é uma propriedade de todos os gases inertes.

Considere um exemplo de herança de formas geométricas. Para descrever a completa variedade de formas simples (círculos, triângulos, retângulos, quadrados, etc.), a melhor forma é criar uma classe base (ADT), que é o predecessor de todas as classes derivadas.

Vamos criar uma classe base CShape, que contém apenas a maioria dos membros comuns que descrevem a forma. Estes membros descrevem propriedades que são características de qualquer forma - o tipo da forma e as coordenadas do ponto de ancoragem principal.

Exemplo:

//--- A classe base da forma (Shape)
class CShape
{
protected:
int m_type; // Tipo de Forma
int m_xpos; // X - coordenada do ponto base
int m_ypos; // Y - coordenada do ponto base
public:
CShape(){m_type=0; m_xpos=0; m_ypos=0;} // construtor
void SetXPos(int x){m_xpos=x;} // define X
void SetYPos(int y){m_ypos=y;} // define Y
};

Sem seguida, criamos novas classes derivadas da classe base, nas quais adicionaremos campos necessários, cada um especificando uma certa classe. Para a forma Círculo, é necessário adicionar um membro que contém o valor do raio. A forma Quadrado é caracterizada pelo valor do lado. Portanto, classes derivadas, herdadas da classe base CShape, serão declaradas como se segue:

//--- A classe derivada círculo (Circle)
class CCircle : public CShape // Depois de um dois pontos, nós definimos a classe base
{ // a partir da qual a herança é feita
private:
int m_radius; // raio do círculo

public:
CCircle(){m_type=1;}// construtor, tipo 1
};

Para a classe do Quadrado, a declaração é semelhante:

//--- a classe derivada quadrado (Square)
class CSquare : public CShape // Depois de um dois pontos, nós definimos a classe base
{ // a partir da qual a herança é feita
private:
int m_square_side; // lado do quadrado

public:
CSquare(){m_type=2;} // construtor, tipo 2
};

Deve-se notar que enquanto um objeto é criado, o construtor da classe base é chamado primeiro, e então o construtor da classe derivada é chamado. Quando um objeto é destruído, primeiro o destrutor da classe derivada é chamado, e então o destrutor da classe base é chamado.

Assim, ao declarar a maioria do membros gerais na classe base, podemos acrescentar membros adicionais nas classes derivadas que especificam uma classe particular. A herança permite criar bibliotecas de código poderosas que podem ser reutilizadas muitas vezes.

A sintaxe para criar uma classe derivada a partir de uma classe já existente é a seguinte:

class class_name :
(public | protected | private) opt base_class_name
{
declaração de membros de classe
};



Um dos aspectos da classe derivada é a visibilidade (abertura) de seus sucessores membros (herdeiros). As palavras-chave public, protected e private são usadas para indicar quão disponíveis os membros da classe base estarão disponíveis para a classe derivada. A palavra-chave public após um dois pontos no cabeçalho de uma classe derivada indica que os membros protegidos e públicos da classe base CShape devem ser herdados como membros protegidos e públicos da classe derivada CCircle.

Os membros privados da classe base não são disponíveis para a classe derivada. A herança pública também significa que classes derivadas (CCircle e CSquare) são CShapes. Isto é, o Quadrado (CSquare) é uma Forma (CShape), mas a Forma não necessariamente tem que ser um Quadrado.

A classe derivada é uma modificação da classe base, ele herda os membros protegidos e públicos da classe base. Os construtores e destrutores da classe base não podem ser herdados. Além de membros da classe base, novos membros são adicionados em uma classe derivada.

A classe derivada pode incluir a implementação de funções membro, diferentes da classe base. Isso não tem nada a ver com uma sobrecarga, quando o significado de um mesmo nome de uma função pode ser diferente para diferentes assinaturas.

Em herança protegida, membros públicos e protegidos da classe base tornam-se membros protegidos da classe derivada. Em herança privada, os membros públicos e protegidos da classe base tornam-se membros privados da classe derivada.

Em herança protegida e privada, a relação "o objeto de uma classe derivada é objeto da classe base" não é verdade. Os tipos protegido e privado de herança são raros, e cada um deles precisam ser usados com cautela.

Deve ser entendido que o tipo de herança (public, protected ou private) não afeta a forma de acessar os membros de classes base na hierarquia de herança a partir de uma classe derivada. Para qualquer tipo de herança, somente membros da classe base declarados com especificadores de acesso public e protected estarão disponíveis fora das classes derivadas. Vamos verificar isso no seguinte exemplo:

#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Exemplo de classe com alguns tipos de acesso |
//+------------------------------------------------------------------+
class CBaseClass
{
private: //--- O membro privado não é disponível a partir de classe derivada
int m_member;
protected: //--- O método protegido é disponível a partir da classe base e suas classes derivadas
int Member(){return(m_member);}
public: // O construtor de classe é disponível para todos os membros
CBaseClass(){m_member=5;return;};
private: //--- Um método particular para atribuir um valor para m_member
void Member(int value) { m_member=value;};

};
//+------------------------------------------------------------------+
//| Classe derivada com erros |
//+------------------------------------------------------------------+
class CDerived: public CBaseClass // especificação da herença pública pode ser omitido, uma vez que é predefinido
{
public:
void Func() // Na classe derivada, defina uma função com chamadas aos membros da classe base
{
//--- Uma tentativa de alterar um membro privado da classe base
m_member=0; // Erro, o membro privado da classe base não é disponível
Member(0); // Erro, o método privado da classe base não é disponível em classes derivadas
//--- Leitura do membro da classe base
Print(m_member); // Erro, o membro privado da classe base não é disponível
Print(Member()); // Sem erro, método protegido é acessível a partir da classe base e suas classes derivadas
}
};

No exemplo acima, CBaseClass tem apenas um método público - o construtor. Construtores são chamados automaticamente na criação de um objeto de classe. Portanto, o membro privado m_member e o método protegido Member() não podem ser chamados do lado de fora. Mas no caso de herança pública, o membro Member() da classe base estará disponível a partir de classes derivadas.

No caso de herança protegida, todos os membros da classe base com acessos público e protegido tornam-se protegidos. Isso significa que membros de dados e métodos públicos da classe base, com herança protegida eles passam a ser disponíveis somente a partir de classes derivadas e de suas derivadas seguintes.

//+------------------------------------------------------------------+
//| Exemplo de classe com alguns tipos de acesso |
//+------------------------------------------------------------------+
class CBaseMathClass
{
private: //--- O membro privado não é disponível a partir de classe derivada
double m_Pi;
public: //--- Obtendo e definindo um valor para m_Pi
void SetPI(double v){m_Pi=v;return;};
double GetPI(){return m_Pi;};
public: // O construtor de classe é disponível para todos os membros
CBaseMathClass() {SetPI(3.14); PrintFormat("%s",__FUNCTION__);};
};
//+------------------------------------------------------------------+
//| Uma classe derivada, em que m_Pi não pode ser modificada |
//+------------------------------------------------------------------+
class CProtectedChildClass: protected CBaseMathClass // Herança protegida
{
private:
double m_radius;
public: //--- Métodos públicos na classe derivada
void SetRadius(double r){m_radius=r; return;};
double GetCircleLength(){return GetPI()*m_radius;};
};
//+------------------------------------------------------------------+
//| Função de inicialização de script |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Ao criar uma classe derivada, o construtor da classe base será chamada automaticamente
CProtectedChildClass pt;
//--- Especifica o raio
pt.SetRadius(10);
PrintFormat("Length=%G",pt.GetCircleLength());
//--- Se comentar a string abaixo, obteremos um erro na etapa de compilação, já que SetPi() é agora protegida
// pt.SetPI(3);

//--- Agora declare um variável da classe base e tente definir a constante Pi igual a 10
CBaseMathClass bc;
bc.SetPI(10);
//--- Aqui está o resultado
PrintFormat("bc.GetPI()=%G",bc.GetPI());
}

O exemplo mostra que os métodos SetPI() e GetPI() na classe base CBaseMathClasse estão abertos e disponíveis para chamadas a partir de qualquer lugar do programa. Mas ao mesmo tempo, para CProtectedChildClasse, que é derivada dela, estes métodos podem ser chamados somente a partir de métodos da classe CProtectedChildClass ou suas classes derivadas.

No caso de herança privada, todos os membros da classe base com acesso público e protegido tornam-se privados, e chamá-los torná-se impossível em herança posterior.

MQL5 não tem herança múltipla.