Non c'è modo per upcast in una classe astratta e non modificarlo ogni volta che una classe è derivata da esso?

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

Domanda

#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

Il compilatore dice

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’

A causa di questo problema, dovrò aggiungere funzioni alla classe Abs ogni volta che creo una nuova classe derivata che eredita da essa (upcasting è obbligatorio per me fare. Il programma che sto progettando lo richiede di essere così). Non voglio toccare la classe di base una volta che è stato creato. Non questo problema viola il principio che una volta che si effettua una classe di base, non sarà necessario modificare mai. Un modo per risolvere questo problema? P.S:. Ho visto il modello di progettazione fabbrica ed i modelli di progettazione del prototipo, ma ciascuno di essi non può sembrano essere in grado di risolverlo

È stato utile?

Soluzione

Beh, io non sono sicuro di capire esattamente quello che vuoi (e perché si vuole in questo modo), ma:

int main()
{
        Abs *bb=new B;
        static_cast<B*>(bb)->bye();
        Abs *cc=new C;
        static_cast<C*>(cc)->sayonara();
}//main

I lavori.

Devi solo essere sicuro che bb è davvero un B* prima di static_cast.

Si può anche utilizzare dynamic_cast che restituirà un puntatore nullo se bb non è del tipo corretto.

Altri suggerimenti

Questa è sconfiggendo lo scopo di eredità e interfacce astratte. bye e sayonara entrambi fanno il (addio dicendo) stessa cosa, solo in diverse lingue. Ciò significa che dovreste avere un metodo say_goodbye astratto che ottiene sovrascritto per le sottoclassi. Suppongo che questo sia un esempio semplificato, così forse si potrebbe descrivere lo scenario attuale in modo che possiamo fornire un aiuto più specifico.

Modifica Se si desidera creare una copia della classe derivata attraverso un'interfaccia astratta, controlla questa domanda . Se si desidera accedere in modo esplicito i diversi attributi dei vostri sottoclassi, si dovrebbe chiedere la vostra auto, se sottoclasse es nemmeno appropriato qui, dal momento che le vostre classi non sembrano avere molto in comune.

int main()
{
        B *bb = new B;
        bb->bye();
        C *cc=new C;
        cc->sayonara();
}//main

non sono più necessari In questo modo i cambiamenti nella classe base:)

fusione dinamica è una scelta sensata. Se stai religioso su calchi dinamici, è possibile utilizzare il modello di progettazione visitatore:

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 quindi si utilizza

Abs* b = new B(); Abs* c = new C();
b->accept(DoSayonara()); // Throw an exception
c->accept(DoSayonara()); // Do what is expected

Fate questo solo quando si ha realmente bisogno.

Se upcasting è obbligatoria ed è necessario chiamare i metodi definiti nelle sottoclassi allora stai facendo male.

Tuttavia, in un dato momento, si sia sapere che un oggetto è una sottoclasse specifica, nel qual caso è possibile in modo dinamico cast a quel tipo, o non fare e non si può essere sicuri di poter chiamare la funzione .

Supponendo che questo è legato al altra domanda , ho cercato di spiegare un modo per implementare quel particolare problema in modo diverso ci .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top