Я реализовал составной шаблон, используя умные указатели, он работает до определенного момента.
Проблема в том, что я просто могу использовать методы, реализованные в интерфейсе, и я не могу использовать методы, определенные в производном классе, без использования dynamic_pointer_cast
и я не хочу этого
Я хочу знать, возможно ли это сделать без использования dynamic_pointer_cast
,
Я слышал, что мне нужно реализовать шаблон посетителя, но я действительно не знаю, как и подходит ли он для этой проблемы.
#include <iostream>
#include <vector>
#include <memory>
class Fruit
{
public:
virtual void getOld() = 0;
};
class Orange : Fruit
{
public:
Orange() {}
void add(std::shared_ptr<Fruit> f)
{
v.push_back(f);
}
std::shared_ptr<Fruit> get(int k)
{
return v[k];
}
void getOld()
{
std::cout << "Orange - I'm old." << std::endl;
}
private:
std::vector<std::shared_ptr<Fruit>> v;
};
class Bitter : public Fruit
{
public:
Bitter() {}
void getOld()
{
std::cout << "Bitter - I'm old." << std::endl;
}
void getNew()
{
std::cout << "Bitter - I'm new." << std::endl;
}
};
int main(int argc, char ** argv)
{
auto orange = new Orange;
orange->add(std::make_shared<Bitter>());
auto bitter = orange->get(0);
bitter->getOld();
return 0;
}
Это работает, как вы можете видеть здесь на предварительный просмотр в реальном времени, но когда я пытаюсь использовать:
int main(int argc, char ** argv)
{
auto orange = new Orange;
orange->add(std::make_shared<Bitter>());
auto bitter = orange->get(0);
bitter->getOld();
bitter->getNew();
return 0;
}
Я получил ошибки:
ошибка: в классе Fruit нет члена с именем getNew
Заранее спасибо.
Проблема здесь, я думаю, в том, что она будет работать с полиморфизмом, но метод ‘getNew’ не существует в родительском классе, поэтому вам нужно определить его и сделать его виртуальным. Это единственный способ сделать это без использования приведения объекта.
С этой линией должно работать.
virtual void getNew() = 0;
Одним из возможных решений является наличие следующей функции в Orange
,
template <typename T>
T* get(int k)
{
return dynamic_cast<T*>(v[k].get());
}
А затем используйте:
auto bitter = orange->get<Bitter>(0);
bitter->getOld();
bitter->getNew();
Это выполняет dynamic_cast
но локализован на Orange
,
Следующая информация может быть найдена о «составной шаблон» от GOF книга. Конечно, это было объяснено на основе графического класса.
ключ Составной шаблон абстрактный класс тот представляет собой и то и другое примитивы а также их контейнеры. Для графической системы этот класс — Графический. Графика объявляет операции как Рисовать которые являются специфическими для графических объектов. Это также объявляет операции, которые все составные объекты разделяют, такие как операции для доступа и управления своими дочерними элементами.
Исходя из вышеприведенного объяснения, мы должны в идеале объявлять все возможные интерфейсы листового и неконечного (контейнерного) типа узла при использовании составного шаблона. Я считаю, что это важно для того, чтобы клиент мог обрабатывать отдельные объекты и композиции объектов равномерно. Поэтому в идеале вы должны объявить свои классы следующим образом, используя этот конкретный шаблон. Любая логика, которая была написана на основе точного типа объекта в клиентском коде, нарушает суть этого шаблона.
//Abstract class which should have all the interface common to
// Composite and Leaf class. It may also provide the default
// implementation wherever appropriate.
class Fruit {
public:
virtual void getOld() = 0;
virtual void getNew() = 0;
virtual void add(std::shared_ptr<Fruit> f) { }
virtual std::shared_ptr<Fruit> get(int index ) {return nullptr; }
virtual ~Fruit() { }
};//Composite Node
class Orange : Fruit {
public:
Orange() {}
void add(std::shared_ptr<Fruit> f) { v.push_back(f); }
std::shared_ptr<Fruit> get(int k) { return v[k]; }
void getOld() { std::cout << "Orange - I'm old." << std::endl; }
void getNew() { std::cout << "Orange - I'm new." << std::endl; }
private:
std::vector<std::shared_ptr<Fruit>> v;
};//Leaf node
class Bitter : public Fruit {
public:
Bitter() {}
void getOld() { std::cout << "Bitter - I'm old." << std::endl; }
void getNew() { std::cout << "Bitter - I'm new." << std::endl; }
};