Exercícios de Exame
Nenhum exercício corresponde a esta pesquisa.
Fundamentos de C++ e texto
Verdadeiro ou falso sobre fundamentos de C++Autoavaliação
Exame, 2019/20
Indique se cada uma das afirmações seguintes sobre C++ é verdadeira (V) ou falsa (F).
- Num programa em C++ é possível fazer a definição
bool private = true;. - Para testar se uma variável
xdo tipointestá no intervalo [-10..10] pode usar-se a instruçãoif (-10 <= x <= 10). - O ciclo
for (int i = 0; i < n; i++) std::cout << (char)('A' + i);escreve no ecrã as primeirasnletras do alfabeto. - Para guardar a palavra "Hello" numa string de C é necessário um array de
charcom pelo menos 6 elementos. - Se
nameé uma variável do tipostd::string, ao executarcin >> name;com o utilizador a escrever "Ana-2003 Porto", o valor atribuído anameé "Ana-2003". - A função
void f(const string &s, int &a)pode ser invocada comf("PROG", 210).
Solução
1: F, 2: F, 3: V, 4: V, 5: V, 6: F.
private é palavra reservada, pelo que a definição da 1 não compila. Em C++, -10 <= x <= 10 avalia primeiro -10 <= x (verdadeiro ou falso, convertido para 0 ou 1) e compara esse resultado com 10, pelo que a 2 é sempre verdadeira para qualquer x — não testa o intervalo. O ciclo da 3 imprime A, B, ... até à n-ésima letra. Uma string de C termina em '\0', pelo que "Hello" precisa de 6 carateres. O operador >> lê apenas até ao primeiro espaço, pelo que a 5 fica com "Ana-2003". Por fim, int &a não pode ligar-se à constante 210, pelo que a 6 é falsa.
Confere a tua resposta:
- A 1 é classificada como falsa:
privateé uma palavra reservada. - A 2 é classificada como falsa: a condição não testa o intervalo.
- A 3 é classificada como verdadeira.
- A 4 é classificada como verdadeira: são 5 carateres mais o terminador.
- A 5 é classificada como verdadeira: a leitura para no primeiro espaço.
- A 6 é classificada como falsa: o segundo argumento não pode ser um literal para um parâmetro por referência não constante.
Normalizar uma linha de texto para maiúsculas e espaçosAutoavaliação
Exame, 2017/18
Escreva uma função string transformLine(string s) que recebe uma string
constituída por letras, espaços e outros carateres e retorna uma string constituída apenas por letras maiúsculas e espaços, substituindo os carateres que não são letras nem espaços pelo caráter espaço. A string recebida como parâmetro não deve ser modificada. Exemplo: para "A very, very short sentence!" a função retorna "A VERY VERY SHORT SENTENCE". Deve usar a função auxiliar void toUpperStr(string* s), que converte para maiúsculas, in loco, todas as letras da string apontada.
Solução
string transformLine(string s)
{
string result = "";
for (size_t i = 0; i < s.length(); i++)
{
char c = s.at(i);
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == ' ')
result += c;
else
result += ' ';
}
toUpperStr(&result);
return result;
}
Cada caráter é testado individualmente: letras e espaços copiam-se, todo o resto passa a espaço. Depois invoca-se toUpperStr sobre a string acumulada, que converte as minúsculas para maiúsculas in loco, e retorna-se essa string. A string original nunca é alterada porque se constrói uma nova.
Confere a tua resposta:
- A função percorre todos os carateres da string original sem a modificar.
- Os carateres que não são letras nem espaços são substituídos por espaço.
- A conversão para maiúsculas é feita com
toUpperStrsobre a string resultante antes de a retornar.
Funções e arrays
Média de classificações num array CAutoavaliação
Exame, 2017/18
Escreva o código da função
float average(const int grades[], int numStudents);
que calcula e retorna a média das numStudents classificações de uma prova, guardadas no array grades. Considere que numStudents é sempre maior ou igual a 1.
Solução
float average(const int grades[], int numStudents)
{
float sum = 0;
for (int i = 0; i < numStudents; i++)
sum += grades[i];
return sum / numStudents;
}
Um array recebido como parâmetro decai para um apontador, pelo que o ciclo percorre as numStudents posições acumulando em sum. A divisão sum / numStudents é feita em vírgula flutuante porque sum é float, devolvendo a média como float.
Confere a tua resposta:
- A função percorre as
numStudentsposições do array acumulando a soma. - A média é devolvida como
float, dividindo a soma pelo número de estudantes.
Hora mais cedo e mais tarde num array de structsAutoavaliação
Exame de Recurso, 2023/24
Considere o tipo time_of_day, definido num ficheiro de cabeçalho, que representa horas com precisão de minutos:
struct time_of_day {
unsigned char h; // horas [0,23]
unsigned char m; // minutos [0,59]
};
Escreva uma função
void minmax(const time_of_day times[], int n, time_of_day& min, time_of_day& max);
que recebe um array times com n > 0 horas válidas e atribui a min e max a hora mais cedo e a hora mais tarde existentes no array. Não pode usar contentores (vector, list, set, ...) nem funções de biblioteca.
Solução
void minmax(const time_of_day times[], int n, time_of_day& min, time_of_day& max)
{
min = max = times[0];
for (int i = 1; i < n; i++)
{
int t = times[i].h * 60 + times[i].m;
int tmin = min.h * 60 + min.m;
int tmax = max.h * 60 + max.m;
if (t < tmin) min = times[i];
if (t > tmax) max = times[i];
}
}
Comparar apenas as horas não chega (por exemplo, 10:50 é maior que 11:05? não, mas 11:05 > 10:50 em horas seria falso se só se olhasse para h). Convertendo cada hora para minutos desde a meia-noite, h * 60 + m, a comparação fica correta. O primeiro elemento serve de candidato inicial a mínimo e máximo.
Confere a tua resposta:
- A função inicializa
minemaxcom o primeiro elemento e percorre o resto do array. - A comparação entre horas tem em conta horas e minutos (por exemplo, convertendo para minutos desde a meia-noite).
- Não usa contentores nem funções de biblioteca.
Heterograma numa string de CAutoavaliação
Exame de Recurso, 2023/24
Uma sequência de carateres é um heterograma se cada letra ocorre no máximo uma vez. Por exemplo, "sun" é um heterograma e "moon" não é (a letra 'o' ocorre mais do que uma vez).
Escreva uma função
bool heterogram(const char s[], char r[]);
tais que:
sé uma string de C com letras maiúsculas ou minúsculas e o caráter espaço; os espaços devem ser ignorados e uma letra minúscula deve ser considerada equivalente à maiúscula correspondente;- a função retorna
truese e só sesé um heterograma; - no retorno,
ré uma string de C em minúsculas com todas as letras repetidas ems, por ordem alfabética (rfica vazia sesfor um heterograma).
Sugestão: use um array interno de 26 posições para contar as letras. Não pode usar classes nem funções de biblioteca (vector, string, sort, ...).
Solução
bool heterogram(const char s[], char r[])
{
int count[26] = {0};
int nrep = 0;
for (int i = 0; s[i] != '\0'; i++)
{
char c = s[i];
if (c == ' ') continue;
if (c >= 'A' && c <= 'Z') c = c - 'A' + 'a';
int idx = c - 'a';
count[idx]++;
if (count[idx] == 2) r[nrep++] = c;
}
r[nrep] = '\0';
// ordenar r (insertion sort, por ser curta)
for (int i = 1; i < nrep; i++)
{
char x = r[i];
int j = i - 1;
while (j >= 0 && r[j] > x) { r[j + 1] = r[j]; j--; }
r[j + 1] = x;
}
return nrep == 0;
}
Cada letra (depois de passar a minúscula) é mapeada para um índice entre 0 e 25. A segunda vez que uma letra aparece, essa letra é acrescentada a r. Como as letras são registadas pela ordem em que aparecem, r precisa de ser ordenada no fim; como há no máximo 26 letras, um insertion sort simples chega. O heterograma é detetado quando nenhuma letra se repete.
Confere a tua resposta:
- A função usa um array de 26 inteiros para contar as ocorrências de cada letra, ignorando espaços e unificando maiúsculas/minúsculas.
- Retorna
falsemal detete a segunda ocorrência de uma letra. rrecebe as letras repetidas em minúsculas e por ordem alfabética, terminada em'\0'.
Ficheiros e dados externos
De um ficheiro de texto a uma lista de palavras ordenadaAutoavaliação
Exame, 2017/18
Considere já implementada a função void decomposeLine(string line, vector<string>* words), que decompõe uma linha de texto nas suas palavras e as acrescenta ao vetor words.
Escreva um programa que lê todas as linhas do ficheiro text.txt, gera a lista com todas as palavras nelas existentes e grava essa lista no ficheiro words.txt, por ordem alfabética, uma palavra por linha. Considere que ambos os ficheiros abrem sempre com sucesso e que as palavras repetidas devem ser mantidas na lista.
Solução
int main()
{
ifstream in("text.txt");
ofstream out("words.txt");
vector<string> total;
string line;
while (getline(in, line))
{
vector<string> words;
decomposeLine(line, &words);
total.insert(total.end(), words.begin(), words.end());
}
in.close();
sort(total.begin(), total.end());
for (const string& w : total)
out << w << endl;
out.close();
return 0;
}
Cada linha lida é decomposta em palavras, que se juntam ao vetor acumulador total com insert. Depois ordena-se o vetor com o algoritmo sort da STL e escreve-se cada palavra numa linha do ficheiro de saída. Como não se usa um set, as repetidas mantêm-se.
Confere a tua resposta:
- O programa lê o ficheiro linha a linha com
getlinee decompõe cada linha comdecomposeLine. - Todas as palavras são acumuladas num único vetor.
- O vetor é ordenado com
sortantes de escrever o ficheiro de saída, uma palavra por linha.
Importar um tabuleiro de Campo Minado de um ficheiroAutoavaliação
Exame, 2019/20
No jogo Campo Minado, as minas estão espalhadas por um tabuleiro retangular. O ficheiro do jogo indica, na primeira linha, o tamanho do tabuleiro (linhas x colunas) e, nas linhas seguintes, a posição de cada mina (linha , coluna). Exemplo para um tabuleiro 10x10:
10 x 10
1 , 0
1 , 1
2 , 4
Implemente o construtor da classe:
class Game {
public:
Game(const string &filename);
// ... outros métodos
private:
vector<vector<char>> mines;
};
O construtor deve importar o conteúdo do ficheiro para o vetor mines, com o tamanho indicado no ficheiro, colocando o caráter 'M' nas células com mina e o caráter espaço nas restantes. Se o ficheiro não existir, o programa deve terminar com código de saída igual a 1. Considere que o ficheiro não contém valores errados.
Solução
Game::Game(const string &filename)
{
ifstream f(filename);
if (!f.is_open())
exit(1);
char sep;
int numLines, numCols, lin, col;
f >> numLines >> sep >> numCols;
mines.resize(numLines, vector<char>(numCols, ' '));
while (f >> lin >> sep >> col)
mines.at(lin).at(col) = 'M';
}
A primeira linha tem o formato 10 x 10, pelo que se lêem dois inteiros separados por um caráter (sep). O vetor é redimensionado para as dimensões lidas, todo preenchido com espaços, e cada par seguinte marca uma mina com 'M'. O ciclo while termina naturalmente no fim do ficheiro. Se o ficheiro não abrir, exit(1) termina o programa com o código pedido.
Confere a tua resposta:
- O construtor abre o ficheiro e termina com
exit(1)se a abertura falhar. - Lê as dimensões e redimensiona o vetor bidimensional preenchido com espaços.
- Lê cada par
linha , colunae coloca'M'na célula correspondente.
Organizar notas por cadeira e por nome de estudanteAutoavaliação
Exame de Recurso, 2023/24
Escreva uma função
void organize_grades(const string& input_fname, const string& output_fname);
que lê as linhas de um ficheiro de entrada, cada uma com um identificador de cadeira, o nome de um estudante e uma nota inteira (por exemplo, L.EIC009 Maria 19), e escreve noutro ficheiro uma secção por cadeira: a secção começa pela linha com o identificador da cadeira, seguida de uma linha por estudante dessa cadeira com o nome e a nota. As secções de saída devem estar ordenadas por identificador de cadeira e, dentro de cada secção, os estudantes por ordem alfabética de nome. Exemplo:
Entrada:
L.EIC009 Maria 19
L.EIC009 Manuel 10
L.EIC008 Alberto 10
L.EIC008 Maria 12
L.EIC009 Alberto 20
Saída:
L.EIC008
Alberto 10
Maria 12
L.EIC009
Alberto 20
Manuel 10
Maria 19
Pode assumir que, em cada cadeira, existe no máximo uma nota por estudante.
Solução
void organize_grades(const string& input_fname, const string& output_fname)
{
ifstream in(input_fname);
ofstream out(output_fname);
map<string, map<string, int>> grades;
string course, name;
int grade;
while (in >> course >> name >> grade)
grades[course][name] = grade;
for (const auto& c : grades)
{
out << c.first << endl;
for (const auto& s : c.second)
out << s.first << ' ' << s.second << endl;
}
}
Um map<string, map<string, int>> associa cada cadeira a um map de nome para nota. Como os map mantêm as chaves ordenadas, ao percorrer a estrutura externa e a interna na ordem natural escrevem-se as secções por cadeira ordenadas e, dentro de cada uma, os estudantes por nome, sem ser preciso chamar sort.
Confere a tua resposta:
- Usa uma estrutura ordenada por chave, como
map<string, map<string, int>>, que garante cadeiras e nomes ordenados. - Lê o ficheiro de entrada linha a linha, separando cadeira, nome e nota.
- Escreve as secções por ordem da chave do map exterior e, dentro de cada uma, por ordem do nome.
Contentores e algoritmos da STL
Gerar um vetor de números aleatóriosAutoavaliação
Exame, 2019/20
Escreva uma função genRandom que gera e retorna um vector<unsigned int> com n números inteiros aleatórios no intervalo [0..m], em que n e m são parâmetros da função. Defina o tipo de retorno e os parâmetros como achar apropriado.
Solução
vector<unsigned int> genRandom(unsigned int n, unsigned int m)
{
vector<unsigned int> v;
for (unsigned int i = 0; i < n; i++)
v.push_back(rand() % (m + 1));
return v;
}
rand() % (m + 1) produz valores uniformes entre 0 e m, inclusive. O ciclo corre n vezes, acrescentando cada valor ao vetor, que é devolvido por valor (a STL trata da cópia).
Confere a tua resposta:
- A função cria um vetor vazio e acrescenta
nelementos compush_back. - Cada elemento é gerado com
rand() % (m + 1), ficando no intervalo [0..m]. - O vetor é devolvido por valor.
Remover de um vetor os elementos comuns a outroAutoavaliação
Exame, 2019/20
Escreva uma função vectorReduce que recebe dois vetores, v1 e v2, e modifica v2, removendo-lhe todos os elementos que também pertencem a v1, e retorna a contagem dos elementos removidos. A função não escreve nada no ecrã. Exemplo: se v1 = {1, 2, 3} e v2 = {2, 4, 2, 5, 3}, após a invocação v2 = {4, 5} e o valor retornado é 3.
Solução
unsigned int vectorReduce(const vector<unsigned int> &v1, vector<unsigned int> &v2)
{
unsigned int count = 0;
for (size_t i = 0; i < v2.size(); )
{
bool found = false;
for (size_t k = 0; k < v1.size(); k++)
if (v2[i] == v1[k]) { found = true; break; }
if (found)
{
v2.erase(v2.begin() + i);
count++;
}
else
i++;
}
return count;
}
Percorre-se v2 elemento a elemento e, para cada um, verifica-se se pertence a v1. Se pertencer, remove-se com erase e incrementa-se o contador; como a remoção desloca os elementos seguintes para a esquerda, o índice só avança quando o elemento atual não é removido. No exemplo, 2, 2 e 3 são removidos, sobrando {4, 5} e com 3 remoções registadas. Alternativamente, pode usar-se o idiom erase-remove com remove_if e find.
Confere a tua resposta:
- A função percorre os elementos de
v1e, para cada um, procura-o emv2. - Cada elemento encontrado é removido de
v2comerasee contado. - O número de elementos removidos é devolvido.
Procurar um valor num vector<string> com findAutoavaliação
Exame, 2017/18
A STL de C++ disponibiliza a função find com o seguinte protótipo:
template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& val);
Diga se é possível usar esta função para procurar o valor "31" numa variável v do tipo vector<string>. Em caso afirmativo, escreva o pedaço de código que procura o valor e escreve uma mensagem a indicar se foi encontrado ou não. Justifique a resposta.
Solução
auto it = find(v.begin(), v.end(), "31");
if (it != v.end())
cout << "Element found";
else
cout << "Element not found";
Sim, é possível: basta passar v.begin() e v.end() como iteradores de entrada e "31" como valor a procurar (a comparação usa operator== de string). A função retorna um iterador para a primeira ocorrência ou para v.end() se não existir, pelo que a comparação com v.end() decide se o valor foi encontrado.
Confere a tua resposta:
- A resposta é afirmativa:
findfunciona com os iteradoresbegin()/end()do vetor. - O código compara o iterador retornado com
v.end()para saber se encontrou. - A justificação refere que
findretorna um iterador para o elemento ou para o fim do intervalo.
Porque falha a declaração de um set<Position>Autoavaliação
Exame, 2017/18
Um programador queria usar num programa uma estrutura de dados do tipo set<Position>, em que Position é a struct
struct Position { int lin, col; };
mas obtuvo um erro de compilação ao declarar variáveis deste tipo. Indique a causa mais provável deste problema e aponte uma solução. Não escreva código.
Solução
Um std::set é um contentor associativo ordenado que, por omissão, usa std::less<Position>, o que exige o operador < para Position. Como a struct não o sobrecarrega, a instanciação do set falha na compilação. A solução é definir bool operator<(const Position&, const Position&) (por exemplo, comparando primeiro lin e depois col) ou declarar o set com um tipo comparador próprio, como set<Position, ComparaPosition>.
Os contentores ordenados da STL (set, map, ...) precisam de uma relação de ordem estrita entre os elementos. Sem operator< para Position, o modelo interno do set não compila. Basta acrescentar a sobrecarga do operador ou fornecer um functor comparador como segundo parâmetro do template.
Confere a tua resposta:
- A justificação indica que
std::setprecisa de comparar elementos comoperator<e a structPositionnão o define. - A solução proposta é sobrecarregar o
operator<paraPositionou passar um comparador/comparação aoset.
Classes e objetos
Registar uma nota só se o estudante estiver matriculadoAutoavaliação
Exame, 2019/20
Considere a classe parcial Student:
class Student {
public:
Student(int id = 0, const string &name = "");
void enrollCourse(Course *course);
bool setGrade(int courseId, int grade);
// ... outros métodos
private:
int id;
string name;
vector<Course *> courses; // UCs em que está matriculado
map<int, int> grades; // notas obtidas (chave = courseId)
};
Escreva o código do método setGrade, que regista a nota grade na cadeira courseId e retorna true, ou retorna false se: (1) o estudante não estiver matriculado nessa cadeira (verificando através de courses), ou (2) já existir uma entrada em grades com a chave courseId.
Solução
bool Student::setGrade(int courseId, int grade)
{
bool isEnrolled = false;
for (auto c : courses)
if (c->getId() == courseId)
{
isEnrolled = true;
break;
}
if (!isEnrolled) return false;
if (grades.find(courseId) != grades.end()) return false;
grades[courseId] = grade;
return true;
}
Percorre-se o vetor de apontadores courses para confirmar a matrícula; se nenhum curso tiver o courseId, retorna-se false. Depois, grades.find(courseId) != grades.end() deteta uma nota já existente. Só se ambas as verificações passarem se insere a nota no map (com grades[courseId] = grade ou insert) e se retorna true.
Confere a tua resposta:
- O método verifica primeiro se existe algum curso em
coursescom o identificador pedido. - Depois verifica se
gradesjá contém a chavecourseId(por exemplo, comfind). - Só regista a nota e retorna
truese nenhuma das verificações falhar.
Média arredondada das notas de um estudanteAutoavaliação
Exame, 2019/20
Considerando ainda a classe Student da pergunta anterior, escreva o código de um método int getAverageGrade() const que retorna a classificação média do estudante em todas as cadeiras registadas em grades, arredondada para o inteiro mais próximo.
Solução
int Student::getAverageGrade() const
{
float sum = 0;
for (auto x : grades)
sum += x.second;
return (int)(sum / grades.size() + 0.5);
}
Num map<int, int>, cada elemento é um par (chave, valor); a nota é o second. Somam-se todos os valores e divide-se pelo número de elementos. Somar 0.5 antes do truncamento para int arredonda para o inteiro mais próximo (para valores positivos).
Confere a tua resposta:
- O método percorre o
mapgradesacumulando a soma das notas (os valores,second). - A média é arredondada para o inteiro mais próximo antes de ser devolvida.
Colocar um navio num tabuleiroAutoavaliação
Exame, 2017/18
No jogo da Batalha Naval, um tabuleiro é representado pela classe parcial:
class Board {
public:
Board(size_t numLines = 10, size_t numColumns = 10);
bool putShip(const Ship &s);
private:
bool canPutShip(Position pos, char dir, size_t size);
size_t numLines, numColumns;
vector<vector<int>> board; // cada elemento = id do navio ou -1 ("mar")
vector<Ship> ships;
};
A classe Ship tem os métodos Position pos() const, char dir() const ('H' ou 'V'), size_t size() const e unsigned int id() const. O método canPutShip já está implementado e verifica se o navio cabe no tabuleiro, na posição e direção dadas, sem sair dos limites nem ocupar células ocupadas.
Escreva o código do método putShip, que tenta colocar o navio s no tabuleiro (modificando board e ships) e retorna true ou false, consoante tenha sido possível ou não.
Solução
bool Board::putShip(const Ship &s)
{
if (!canPutShip(s.pos(), s.dir(), s.size()))
return false;
if (s.dir() == 'H')
for (size_t i = 0; i < s.size(); i++)
board.at(s.pos().lin).at(s.pos().col + i) = s.id();
else
for (size_t i = 0; i < s.size(); i++)
board.at(s.pos().lin + i).at(s.pos().col) = s.id();
ships.push_back(s);
return true;
}
Primeiro delega-se a validação em canPutShip. Se passar, preenchem-se as size células a partir do canto superior esquerdo (pos()), na horizontal (col + i) ou na vertical (lin + i), com o identificador do navio, e regista-se o navio em ships. A devolução é true apenas se o navio ficou colocado.
Confere a tua resposta:
- O método chama
canPutShipcom a posição, direção e tamanho do navio e retornafalsese não for possível. - Se for possível, preenche as células do navio em
boardcom o identificador do navio, na horizontal ou na vertical consoantedir(). - O navio é acrescentado a
shipse o método retornatrue.
Herança e polimorfismo
Saída de um programa com funções virtuais e cópia por valorAutoavaliação
Exame, 2017/18
Considere as classes e o programa seguintes:
class Base {
public:
Base(int a) { _a = a; }
virtual void show() const { cout << _a; }
protected:
int _a;
};
class Derived : public Base {
public:
Derived(int a, int b) : Base(a) { _b = b; }
void show() const { cout << _a << ' ' << _b; }
private:
int _b;
};
int main()
{
Derived d(2, 3);
d.show();
cout << endl;
Base b = d;
b.show();
cout << endl;
Base *pb = &d;
pb->show();
cout << endl;
}
(a) Qual a saída do programa? (b) Qual seria a saída se o qualificador virtual fosse retirado de show() na classe Base? (c) O que acontece se protected em Base for substituído por private? Justifique.
Solução
(a) Com virtual: 23, 2, 23. (b) Sem virtual na base: 23, 2, 2. (c) Com private em vez de protected, erro de compilação.
d.show() chama o método de Derived (23). A atribuição Base b = d; copia apenas a parte base do objeto (slicing), pelo que b.show() chama Base::show e imprime 2. A chamada pb->show() é dinâmica por causa de virtual, apesar de o apontador ser de Base, e imprime 23. Sem virtual, essa chamada resolve estaticamente para Base::show, imprimindo 2. Se _a fosse private, a classe Derived não poderia aceder-lhe no seu próprio show(), pelo que o código nem compilava.
Confere a tua resposta:
- A saída com
virtualé 23, 2, 23 (um valor por linha). - Sem
virtual, a terceira chamada mostra apenas 2. - Com
private, o programa não compila, porqueDeriveddeixaria de aceder a_a.
Hierarquia Vehicle, Car e Bike com displayInfoAutoavaliação
Exame de Recurso, 2023/24
Considere a classe base Vehicle, num ficheiro de cabeçalho:
class Vehicle {
protected:
std::string make; // marca
std::string model;
int year;
public:
Vehicle(std::string make, std::string model, int year)
: make(make), model(model), year(year) {}
virtual void displayInfo() const {
std::cout << make << " " << model << " " << year << " ";
}
};
Escreva a implementação das classes Car e Bike, que herdam de Vehicle e acrescentam, respetivamente, o atributo e método int numberOfDoors() const e o atributo e método bool isElectric() const. Ambas devem sobrepor o método displayInfo() para mostrar também a sua informação específica, para além da informação base.
Solução
class Car : public Vehicle {
public:
Car(std::string make, std::string model, int year, int numberOfDoors)
: Vehicle(make, model, year), numberOfDoors_(numberOfDoors) {}
int numberOfDoors() const { return numberOfDoors_; }
void displayInfo() const override {
Vehicle::displayInfo();
std::cout << numberOfDoors_ << " doors";
}
private:
int numberOfDoors_;
};
class Bike : public Vehicle {
public:
Bike(std::string make, std::string model, int year, bool isElectric)
: Vehicle(make, model, year), isElectric_(isElectric) {}
bool isElectric() const { return isElectric_; }
void displayInfo() const override {
Vehicle::displayInfo();
std::cout << (isElectric_ ? "electric" : "muscular");
}
private:
bool isElectric_;
};
Cada subclasse chama o construtor da base com Vehicle(make, model, year) na lista de inicialização e guarda o atributo próprio. O método displayInfo() sobreposto chama primeiro Vehicle::displayInfo() para reutilizar a saída base e depois acrescenta a informação específica, com override para o compilador confirmar a sobreposição do método virtual.
Confere a tua resposta:
CareBikeherdam publicamente deVehiclee chamam o construtor da base.- Cada uma guarda o seu atributo extra (
numberOfDoors_/isElectric_) e expõe o método de acesso pedido. - Ambas sobrepõem
displayInfo()chamandoVehicle::displayInfo()e acrescentando a informação específica.