Não há como aprimorar uma classe abstrata e não modificá -la sempre que uma classe é derivada dela?

StackOverflow https://stackoverflow.com/questions/3829220

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.

Foi útil?

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 .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top