У меня есть два варианта одного и того же метода. У меня также есть экземпляр типа базового класса, но я не знаю, к какому конкретному классу он относится. Теперь я хочу автоматически выбирать подходящий метод в зависимости от фактического типа объекта. Это кажется невозможным, и единственное решение, которое я могу придумать, - это проверить все возможности с помощью кастинга. Однако должно быть более приятное решение.
Вот мой минимальный пример:
// Example program
#include <iostream>
#include <string>
#include <memory>
class A
{
public:
virtual void bar() const = 0;
};
class B : public A
{
public:
void bar() const
{
std::cout << "B.bar()" << std::endl;
}
};
class C : public A
{
public:
void bar() const
{
std::cout << "C.bar()" << std::endl;
}
};
class Z
{
public:
Z(int variable) : m_variable(variable) {};
void foo(std::shared_ptr<B> b)
{
std::cout << "Calling foo(B) method! " << m_variable << std::endl;
b->bar();
}
void foo(std::shared_ptr<C> c)
{
std::cout << "Calling foo(C) method!" << m_variable << std::endl;
c->bar();
}
private:
int m_variable;
};
int main()
{
std::shared_ptr<A> b(new B());
Z z(42);
//z.foo(b); // This doesn't work
// But this does
std::shared_ptr<B> b_cast = std::dynamic_pointer_cast<B>(b);
if (b_cast.get())
z.foo(b_cast);
}
На данный момент мне приходится прибегать к dynamic_pointer_cast, но я считаю его некрасивым и не очень удобным в обслуживании.
Я также не хочу добавлять функциональность foo()
к классам B
и C
, потому что это небольшие независимые структуры данных, с которыми работают многие другие классы.
Большое спасибо!
РЕДАКТИРОВАТЬ: В исходном посте я слишком упростил. Новый пример должен прояснить ситуацию.
2 ответа
Добавьте чистую виртуальную функцию foo()
в базовый класс и переопределите в последующих производных классах. Затем пусть ваша глобальная функция foo()
(которая не имеет ничего общего с функциями-членами с тем же именем) примет ссылку на std::shared_ptr
const в качестве параметра:
#include <iostream>
#include <memory>
class A{
public:
virtual void foo() = 0;
};
class B : public A{
public:
void foo() override{
std::cout << "Calling foo(B) method!" << std::endl;
}
};
class C : public A{
public:
void foo() override{
std::cout << "Calling foo(C) method!" << std::endl;
}
};
void foo(const std::shared_ptr<A>& param){
param->foo();
}
int main(){
std::shared_ptr<A> b = std::make_shared<B>();
std::shared_ptr<A> c = std::make_shared<C>();
foo(b);
foo(c);
}
foo
функцией-членом другого класса, который работает с объектами типов B
и C
. Так как у меня много таких классов, я не хочу добавлять все эти функции к самим B
и C
. Результат foo()
также сильно зависит от переменных-членов реализующего класса.
Как указал BoBTFish, шаблон посетителя является потенциальным решением этой проблемы:
// Example program
#include <iostream>
#include <string>
#include <memory>
class B;
class C;
class Visitor
{
public:
virtual void visit(B* b) const = 0;
virtual void visit(C* b) const = 0;
};
class A
{
public:
virtual void bar() const = 0;
virtual void accept(const Visitor* visitor) = 0;
};
class B : public A
{
public:
void bar() const
{
std::cout << "B.bar()" << std::endl;
}
void accept(const Visitor* visitor)
{
visitor->visit(this);
}
};
class C : public A
{
public:
void bar() const
{
std::cout << "C.bar()" << std::endl;
}
void accept(const Visitor* visitor)
{
visitor->visit(this);
}
};
class Z : public Visitor
{
public:
Z(int variable) : m_variable(variable) {};
void visit(B* b) const
{
std::cout << "Calling foo(B) method! " << m_variable << std::endl;
b->bar();
}
void visit(C* c) const
{
std::cout << "Calling foo(C) method!" << m_variable << std::endl;
c->bar();
}
private:
int m_variable;
};
int main()
{
std::shared_ptr<A> b(new B());
Z z(42);
b->accept(&z);
}
Большое спасибо!
Похожие вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который должен быть) скомпилирован с помощью компилятора C ++. Используйте тег для конкретной версии для вопросов, связанных с конкретной версией стандарта [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] или [C ++ 23] и т. Д. .
a = b;
приводит к разрезанию. (Здесь нет никаких данных-членов, но, в частности, эта строка не превращаетa
внезапно вB
.)