Não há como aprimorar uma classe abstrata e não modificá -la sempre que uma classe é derivada dela?
-
26-09-2019 - |
Pergunta
#include<iostream>
using namespace std;
class Abs
{
public:
virtual void hi()=0;
};
class B:public Abs
{
public:
void hi() {cout<<"B Hi"<<endl;}
void bye() {cout<<"B Bye"<<endl;}
};
class C:public Abs
{
public:
void hi() {cout<<"C Hi"<<endl;}
void sayonara() {cout<<"C Sayonara"<<endl;}
};
int main()
{
Abs *bb=new B;
bb->bye();
Abs *cc=new C;
cc->sayonara();
}//main
O compilador diz
test2.cpp: In function ‘int main()’:
test2.cpp:26: error: ‘class Abs’ has no member named ‘bye’
test2.cpp:28: error: ‘class Abs’ has no member named ‘sayonara’
Por causa desse problema, terei que adicionar funções à classe ABS cada vez que crio uma nova classe derivada que herda dela (é obrigatório para mim. O programa que estou planejando exige que seja assim). Não quero tocar a classe base depois de criada. Esse problema não viola o princípio de que, depois de fazer uma classe base, você não precisará modificá -lo nunca. Alguma maneira de resolver esse problema? PS: Eu vi o padrão de design de fábrica e os padrões de design de protótipo, mas os dois não conseguem ser capazes de resolvê -lo.
Solução
Bem, não tenho certeza de entender exatamente o que você quer (e por que você quer dessa maneira), mas:
int main()
{
Abs *bb=new B;
static_cast<B*>(bb)->bye();
Abs *cc=new C;
static_cast<C*>(cc)->sayonara();
}//main
Vai funcionar.
Você só tem que ter certeza disso bb
é realmente um B*
antes de você static_cast
.
Você também pode usar dynamic_cast
que retornará um ponteiro nulo se bb
não é do tipo correto.
Outras dicas
Isso está derrotando o objetivo da herança e interfaces abstratas. bye
e sayonara
Ambos fazem a mesma coisa (dizendo adeus), apenas em diferentes idiomas. Isso significa que você deve ter um resumo say_goodbye
Método que é substituído para subclasses. Suponho que este seja um exemplo simplificado, então talvez você possa descrever seu cenário real para que possamos fornecer ajuda mais específica.
Editar Se você deseja criar uma cópia da classe derivada através de uma interface abstrata, confira essa questão. Se você deseja acessar explicitamente os diferentes atributos de suas subclasses, você deve se perguntar se subclassificar ES até apropriado aqui, pois suas aulas não parecem ter muito em comum.
int main()
{
B *bb = new B;
bb->bye();
C *cc=new C;
cc->sayonara();
}//main
Dessa forma, as modificações na classe base não são mais necessárias :)
A fundição dinâmica é uma opção sensata. Se você é religioso sobre elencos dinâmicos, pode usar o padrão de design do visitante:
struct Abs;
struct B;
struct C;
struct Visitor
{
virtual ~Visitor() {}
// Provide sensible default actions
virtual void visit(Abs&) const { throw "not implemented"; }
virtual void visit(B& b) const { visit(static_cast<Abs&>(b)); }
virtual void visit(C& c) const { visit(static_cast<Abs&>(c)); }
};
struct Abs
{
virtual ~Abs() {}
virtual void hi() = 0;
virtual void accept(Visitor const& v) { v.visit(*this); }
};
struct B : Abs
{
void hi() { ... }
void accept(Visitor const& v) { v.visit(*this); }
void bye() { ... }
};
struct C : Abs
{
void hi() { ... }
void accept(Visitor const& v) { v.visit(*this); }
void sayonara() { ... }
};
struct DoSayonara : Visitor
{
void visit(C& c) const { c.sayonara(); }
};
struct DoBye : Visitor
{
void visit(B& b) const { b.bye(); }
};
struct ByeOrSayonara : Visitor
{
void visit(B& b) const { b.bye(); }
void visit(C& c) const { c.sayonara(); }
};
E então você usa
Abs* b = new B(); Abs* c = new C();
b->accept(DoSayonara()); // Throw an exception
c->accept(DoSayonara()); // Do what is expected
Faça isso apenas quando você realmente precisar.
Se o upcasting for obrigatório e você precisar chamar métodos definidos nas subclasses, estará fazendo errado.
No entanto, em um determinado momento, você sabe que um objeto é uma subclasse específica; nesse caso, você pode ser fundido dinamicamente para esse tipo, ou não e não pode ter certeza de que pode chamar a função.
Supondo que isso esteja relacionado ao seu outra questão, Eu tentei explicar uma maneira de implementar esse problema em particular de uma maneira diferente lá.