Herança Múltipla
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 53 de 104.
O C++ permite que uma classe herde de múltiplas classes base simultaneamente. Isso é chamado de herança múltipla e permite combinar recursos de diferentes hierarquias de classes.
Para herdar de múltiplas classes, separe-as com vírgulas:
class Printer {
public:
void print() {
std::cout << "Printing document" << std::endl;
}
};
class Scanner {
public:
void scan() {
std::cout << "Scanning document" << std::endl;
}
};
class MultiFunctionDevice : public Printer, public Scanner {
public:
void copy() {
scan();
print();
}
};A classe MultiFunctionDevice agora tem acesso a métodos de ambos Printer e Scanner:
MultiFunctionDevice mfd;
mfd.print(); // De Printer
mfd.scan(); // De Scanner
mfd.copy(); // Seu próprio métodoOs construtores são chamados na ordem em que as classes base são listadas na declaração de herança (da esquerda para a direita), e os destrutores na ordem inversa. Você pode passar argumentos para cada construtor base na lista de inicialização:
class MultiFunctionDevice : public Printer, public Scanner {
public:
MultiFunctionDevice() : Printer(), Scanner() {}
};Um problema potencial surge quando ambas as classes base possuem um membro com o mesmo nome. Isso cria ambiguidade, e você deve usar o operador de resolução de escopo para especificar qual deles você se refere:
class A { public: void show() {} };
class B { public: void show() {} };
class C : public A, public B {};
C obj;
obj.A::show(); // Chama a versão de A
obj.B::show(); // Chama a versão de BHerança múltipla é poderosa, mas pode levar a situações complexas, especialmente quando as classes base compartilham um ancestral comum. Exploraremos esse desafio na próxima aula.
Desafio
FácilVamos construir um sistema de dispositivos domésticos inteligentes que combina recursos de várias classes base usando herança múltipla. Você criará dispositivos que podem se conectar ao WiFi e ser controlados por voz, e então combinará esses recursos em um alto-falante inteligente unificado.
Você organizará seu código em três arquivos:
WiFiDevice.h: Defina uma classeWiFiDeviceque representa qualquer dispositivo capaz de se conectar a uma rede:- Um membro protegido
std::string networkName - Um construtor que recebe um nome de rede e o armazena
- Um método público
connect()que imprime:Connecting to WiFi: <networkName> - Um método público
status()que imprime:WiFi Status: Connected
- Um membro protegido
VoiceControl.h: Defina uma classeVoiceControlque representa qualquer dispositivo com recursos de voz:- Um membro protegido
std::string assistantName - Um construtor que recebe um nome de assistente e o armazena
- Um método público
listen()que imprime:<assistantName> is listening... - Um método público
status()que imprime:Voice Status: Active
- Um membro protegido
main.cpp: Leia três entradas (cada uma em uma linha separada):- Nome do dispositivo (string)
- Nome da rede WiFi (string)
- Nome do assistente de voz (string)
Defina uma classe
SmartSpeakerque herda publicamente deWiFiDeviceeVoiceControl:- Um membro privado
std::string deviceName - Um construtor que recebe todos os três parâmetros, passa o nome da rede para
WiFiDevicee o nome do assistente paraVoiceControlusando a lista de inicialização, e armazena o nome do dispositivo - Um método
powerOn()que imprime:<deviceName> powering on..., e então chamaconnect()elisten() - Um método
showAllStatus()que imprime o nome do dispositivo e, em seguida, usa o operador de resolução de escopo para chamar ambos os métodosstatus()para resolver a ambiguidade
Crie um objeto
SmartSpeakercom os valores de entrada. ChamepowerOn(), imprima uma linha em branco e, em seguida, chameshowAllStatus().
Por exemplo, com as entradas Echo, HomeNetwork, e Alexa:
Echo powering on...
Connecting to WiFi: HomeNetwork
Alexa is listening...
Echo Status:
WiFi Status: Connected
Voice Status: ActiveO método showAllStatus() deve imprimir o nome do dispositivo seguido por " Status:" em uma linha, e então chamar o método status() de cada classe base usando WiFiDevice::status() e VoiceControl::status() para evitar ambiguidade, já que ambas as classes base possuem um método com o mesmo nome.
Folha de consulta
C++ suporta herança múltipla, permitindo que uma classe herde de múltiplas classes base simultaneamente:
class DerivedClass : public BaseClass1, public BaseClass2 {
// Corpo da classe
};A classe derivada tem acesso aos membros de todas as classes base:
class Printer {
public:
void print() {
std::cout << "Printing document" << std::endl;
}
};
class Scanner {
public:
void scan() {
std::cout << "Scanning document" << std::endl;
}
};
class MultiFunctionDevice : public Printer, public Scanner {
public:
void copy() {
scan(); // De Scanner
print(); // De Printer
}
};Os construtores das classes base são chamados na ordem em que aparecem na lista de herança (da esquerda para a direita). Use a lista de inicialização para passar argumentos para cada construtor base:
class MultiFunctionDevice : public Printer, public Scanner {
public:
MultiFunctionDevice() : Printer(), Scanner() {}
};Quando múltiplas classes base possuem membros com o mesmo nome, use o operador de resolução de escopo para resolver a ambiguidade:
class A { public: void show() {} };
class B { public: void show() {} };
class C : public A, public B {};
C obj;
obj.A::show(); // Chama a versão de A
obj.B::show(); // Chama a versão de BExperimente você mesmo
#include <iostream>
#include <string>
#include "WiFiDevice.h"
#include "VoiceControl.h"
using namespace std;
// TODO: Definir a classe SmartSpeaker que herda publicamente de WiFiDevice e VoiceControl
// - Membro privado: deviceName (string)
// - Construtor: recebe deviceName, networkName, assistantName
// Use a lista de inicialização para passar networkName para WiFiDevice e assistantName para VoiceControl
// - Método powerOn(): imprime "<deviceName> powering on...", então chama connect() e listen()
// - Método showAllStatus(): imprime "<deviceName> Status:", então chama ambos os métodos status()
// usando resolução de escopo (WiFiDevice::status() e VoiceControl::status())
class SmartSpeaker {
// TODO: Implementar a classe SmartSpeaker aqui
};
int main() {
string deviceName, networkName, assistantName;
getline(cin, deviceName);
getline(cin, networkName);
getline(cin, assistantName);
// TODO: Criar um objeto SmartSpeaker com os valores de entrada
// TODO: Chamar powerOn()
// TODO: Imprimir uma linha em branco
// TODO: Chamar showAllStatus()
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico