Могу ли я выполнить наследование вне класса в C ++ 11?

0

Скажем, я хочу перегрузить функцию за пределами моих классов разными типами указателей. Могу ли я сделать это на С++ 11?

struct Bird;
struct Bear;

struct Animal {
    virtual Bird* AsBird() = 0;
    virtual Bear* AsBear() = 0;
};
struct Bird : public Animal{
    virtual Bird* AsBird(){ return this; }
    virtual Bear* AsBear(){ return NULL; }
};
struct Bear : public Animal{
    virtual Bird* AsBird(){ return NULL; }
    virtual Bear* AsBear(){ return this; }
};

void Print(Animal* a){
    cout << "I don't know what animal this is!" << endl;
}

void Print(Bear* b){
    cout << "That a bear!" << endl;
}

void Print(Bird* b){
    cout << "That a bird!" << endl;
}

int main(int argc, char* argv[]){

    Animal* a = new Bear;

    Bear* bear;
    Bird* bird;

    if (bear = a->AsBear()){
        Print(bear);
    } else if (bird = a->AsBird()){
        Print(bird);
    }

    return 0;
}

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

  • 0
    AsBear() ... вы просто повторно реализует dynamic_cast ?
  • 0
    Метод, возвращающий NULL при ошибке, всегда является ошибкой, ожидающей своего появления.
Теги:
c++11
templates
oop
inheritance

4 ответа

2

То, что вы сделали, - это перегрузка функции Print free, изменяя тип ее параметра, нет наследования, и это совершенно законно.

Но вам это не нужно (или любое подобное dynamic_cast-like, как и вы): то, что вам нужно сделать, это добавить virtual void Print() const = 0 в ваш базовый класс Animal и переопределить его в каждом производном классе.

Пример:

struct Animal {
    virtual void Print() const = 0;
};

struct Bird : public Animal{
    void Print() const { cout << "That a bird!\n"; }
};

struct Bear : public Animal{
    void Print() const { cout << "That a bear!\n"; }
};

int main(){

    Animal* a = new Bear;
    a->Print();

    Animal* b = new Bird;
    b->Print();
}
1

Это выглядит как пример использования шаблона посетителя.

struct Bird;
struct Bear;

struct Visitor
{
    virtual void Visit(Bird& x) = 0;
    virtual void Visit(Bear& x) = 0;
};

struct PrintVisitor : Visitor
{
    void Visit(Bird& x) override { cout << "That a bird!" << endl; };
    void Visit(Bear& x) override { cout << "That a bear!" << endl; };
};

struct Animal
{
    virtual void Accept(Visitor& v) = 0;
};

struct Bird : public Animal
{
    void Accept(Visitor& v) override { v.Visit(*this); }
};

struct Bear : public Animal
{
    void Accept(Visitor& v) override { v.Visit(*this); }
};

int main(int argc, char* argv[])
{
    Bear bear;
    Bird bird;

    PrintVisitor visitor;      

    Animal* a = &bear;
    a->Accept(visitor);

    a = &bird;
    a->Accept(visitor);
}

Конечно, проще было бы сделать Print виртуальной функцией-членом.

1

Как отметил квантв, традиционный способ заключается в добавлении виртуальной функции в вашу иерархию классов.

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

struct Animal {
    virtual ~Animal() {} // base class must have a virtual method to use dynamic_cast
};

...

if (bear = dynamic_cast<Bear*>(a)){
    Print(bear);
} else if (bird = dynamic_cast<Bird*>(a)){
    Print(bird);
}

Это немного лучше, чем у вас: если вы добавите другой наследующий класс, вам не придется менять свой базовый класс; вы должны только изменить main функцию и добавить новую функцию печати.

Если это все еще "ужасно", возможно, вы должны сделать Print виртуальной функцией.

0

Функции AsBear, AsBird, вы просто переопределили dynamic_cast.

Что касается перегрузок Print, самое простое решение здесь - сделать virtual функцию Print в иерархии Animal.

Моим рекомендуемым решением было бы использовать шаблон посетителя. С тех пор, как вы пытаетесь сделать это, отделив функцию Print и иерархию классов.

#include <iostream>

struct Bird;
struct Bear;

struct Animal {

  struct Visitor {
    virtual void operator()(const Bird *) const = 0;
    virtual void operator()(const Bear *) const = 0;
  };

  virtual void Accept(const Visitor &visitor) const = 0;

};

struct Bird : public Animal {

  virtual void Accept(const Visitor &visitor) const override {
    visitor(this);
  }

};

struct Bear : public Animal {

  virtual void Accept(const Visitor &visitor) const override {
    visitor(this);
  }

};

struct Print : public Animal::Visitor {
  virtual void operator()(const Bird *) const override {
    std::cout << "Bird" << std::endl;
  }
  virtual void operator()(const Bear *) const override {
    std::cout << "Bear" << std::endl;
  }
};

int main() {
  Bird bird;
  Animal *animal = &bird;
  animal->Accept(Print());
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню