Имеется иерархия классов, в которой A — базовый, B — потомок. У A есть защищенное поле m_i, а у B добавляется защищенное поле m_j. Требуется написать метод setParams такой, что при использовании экземпляра класса из разрабатываемой иерархии, он будет принимать правильные параметры и правильно их устанавливать. Т.е. для объекта класса A пример одно значение и установит поле m_i, а для B примет два значения и установит поля m_i и m_j:
A<int>* ptr = new B<int>;
ptr->setParams(1,2); // m_i=1, m_j=2
A<int>* ptr = new A<int>;
ptr->setParams(3); // m_i=3
моя не очень удачная попытка
http://ideone.com/mataBZ
template<class T>
class A {
protected:
T m_i;
virtual void m_set(T i)
{
m_i=i;
};
public:
template<typename ... Args>
void setParams( Args&&... params )
{
m_set(std::forward<Args>(params)...);
}
virtual void show()
{
cout << m_i << endl;
}
};
template<class T, typename ... args>
class B: public A<T> {
protected:
using A<T>::m_i;
T m_j;
virtual void m_set(T i, T j)
{
m_i=i;
m_j=j;
}
public:
virtual void show() override
{
cout << m_i << ':' << m_j << endl;
}
};
int main() {
auto a = new A<int>;
a->setParams(22);
a->show();
A<int>* b = new B<int>;
a->setParams(22,23);
a->show();
return 0;
}
Здравствуйте, gencoder, Вы писали:
G>G>A<int>* ptr = new B<int>;
ptr->>setParams(1,2); // m_i=1, m_j=2
G>
Судя по тому что родитель ничего не знает о потомке, здесь придётся стирать типы. Например запихнуть std::tuple с параметрами (или указателями на них) в boost::any, а в потомке сделать any_cast (либо сделать более эффективный аналог any для данного случая — тут можно обойтись без аллокации, так как данные живут вверху стэка).
Если опустить runtime проверку типа (что делать в большинстве случаев не нужно), то достаточно передавать void* на tuple, а в потомке делать static_cast.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, gencoder, Вы писали:
G>>G>>A<int>* ptr = new B<int>;
ptr->>>setParams(1,2); // m_i=1, m_j=2
G>>
EP>Судя по тому что родитель ничего не знает о потомке, здесь придётся стирать типы. Например запихнуть std::tuple с параметрами (или указателями на них) в boost::any, а в потомке сделать any_cast (либо сделать более эффективный аналог any для данного случая — тут можно обойтись без аллокации, так как данные живут вверху стэка).
EP>Если опустить runtime проверку типа (что делать в большинстве случаев не нужно), то достаточно передавать void* на tuple, а в потомке делать static_cast.
ставиться цель: обойти static_cast.
со static_cast можно вообще ничего не воротить, а просто при наличии указателя ptr на базовый класс преобразовать его в указатель на конкретно переданный класс, например работаем с unique_prt:
auto ptrB = static_cast<B<T>*>(ptr.get());
// а затем работаем как с B
ptrB->setSpecBParams(/*...*/);
вот такие вещи, как раз то и хотелось бы исключить из кода.
Здравствуйте, gencoder, Вы писали:
G>ставиться цель: обойти static_cast.
Стирать типы придётся. Вот представь что компилятору виден только класс A:
#include "a.hpp"
void foo(A<int> *a)
{
a->setParams(1, 2., '3');
}
каким образом он должен узнать ожидаемое количество параметров и их типы, и в случае чего выдать ошибку компиляции при неправильном вызове setParams? А главное как он должен различить вызов foo с B<int>* от вызова foo с C<int>*? Это разруливается только динамически, то есть в рантайме.
По тем же соображениям не получится передать через заранее типизированный канал объект (или объекты) произвольного типа не стирая этот тип каким-либо образом.
G>со static_cast можно вообще ничего не воротить, а просто при наличии указателя ptr на базовый класс преобразовать его в указатель на конкретно переданный класс
В этом случае на стороне пользователя нужно знать конкретный тип объекта. Он известен?
Ты лучше попробуй описать изначальную задачу, для чего это вообще потребовалось?