Разве нет способа превратить в абстрактный класс и не изменять его каждый раз, когда класс выводится из него? - PullRequest
3 голосов
/ 30 сентября 2010
#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

Компилятор говорит:

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’

Из-за этой проблемы мне придется добавлять функции в класс Abs каждый раз, когда я создаю новый производный класс, который наследуется от него (Upcasting является обязательнымдля меня. Программа, которую я планирую, требует, чтобы это было так).Я не хочу прикасаться к базовому классу после его создания.Не нарушает ли эта проблема принцип, согласно которому после создания базового класса вам не нужно будет его изменять никогда.Любой способ решить эту проблему?PS: Я видел шаблон проектирования фабрики и шаблоны проектирования прототипа, но оба они, похоже, не могут его решить.

Ответы [ 5 ]

4 голосов
/ 30 сентября 2010

Это отрицание цели наследования и абстрактных интерфейсов. bye и sayonara оба делают одно и то же (прощаясь), только на разных языках. Это означает, что у вас должен быть абстрактный метод say_goodbye, который переопределяется для подклассов. Я предполагаю, что это упрощенный пример, поэтому, возможно, вы могли бы описать ваш реальный сценарий, чтобы мы могли предоставить более конкретную помощь.

Редактировать Если вы хотите создать копию производного класса через абстрактный интерфейс, проверьте этот вопрос . Если вы хотите получить явный доступ к различным атрибутам ваших подклассов, вам следует спросить себя, подходит ли здесь подклассы, так как у ваших классов, похоже, мало общего.

3 голосов
/ 30 сентября 2010

Ну, я не уверен, что точно понимаю, что вы хотите (и почему вы хотите именно так), но:

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

Будет работать.

Вы просто должны бытьубедитесь, что bb действительно B* перед вами static_cast.

Вы также можете использовать dynamic_cast, который будет возвращать нулевой указатель, если bb имеет неправильный тип.

1 голос
/ 30 сентября 2010

Динамическое приведение является разумным вариантом. Если вы религиозны в отношении динамических приведений, вы можете использовать шаблон дизайна посетителя:

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(); }
};

и затем вы используете

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

Делайте это только тогда, когда вам это действительно нужно.

1 голос
/ 30 сентября 2010
int main()
{
        B *bb = new B;
        bb->bye();
        C *cc=new C;
        cc->sayonara();
}//main

Таким образом, изменения в базовом классе больше не нужны:)

0 голосов
/ 30 сентября 2010

Если обновление является обязательным, и вам нужно вызывать методы, определенные в подклассах, тогда вы делаете это неправильно.

Однако в определенный момент времени вы либо знаете, что объект является конкретным подклассом, в этом случае вы можете динамически приводить к этому типу, или вы не можете и не можете быть уверены, что можете вызвать функцию.

Предполагая, что это связано с вашим другим вопросом ,Я пытался объяснить способ реализации этой конкретной проблемы другим способом там .

...