Довольно сложно объяснить, что я пытаюсь сделать, я попробую: представьте себе базу class A
, которая содержит некоторые переменные, и набор классов, производных от A
, которые все реализуют некоторый метод bool test()
который работает с переменными, унаследованными от A
.
class A {
protected:
int somevar;
// ...
};
class B : public A {
public:
bool test() {
return (somevar == 42);
}
};
class C : public A {
public:
bool test() {
return (somevar > 23);
}
};
// ... more classes deriving from A
Теперь у меня есть экземпляр class A
, и я установил значение somevar
.
int main(int, char* []) {
A a;
a.somevar = 42;
Теперь мне нужен какой-то контейнер, который позволяет перебирать элементы i
этого контейнера, вызывая i::test()
в контексте a
..., то есть:
std::vector<...> vec;
// push B and C into vec, this is pseudo-code
vec.push_back(&B);
vec.push_back(&C);
bool ret = true;
for(i = vec.begin(); i != vec.end(); ++i) {
// call B::test(), C::test(), setting *this to a
ret &= ( a .* (&(*i)::test) )();
}
return ret;
}
Как я могу это сделать? Я пробовал два метода:
- принудительное приведение из B :: * к A :: *, адаптация указателя для вызова метода типа для объекта другого типа (работает, но кажется плохим);
- использование std :: bind + решение выше, безобразный хак;
- изменив сигнатуру
bool test()
так, чтобы она принимала аргумент типа const A&
вместо наследования от A, мне не очень нравится это решение, потому что somevar должен быть общедоступным.
EDIT:
Решение (1):
typedef bool (A::*)() mptr;
std::vector<mptr> vec;
vec.push_back(static_cast<mptr>(&T::test));
std::vector<mptr>::iterator i;
for(i = vec.begin(); i != vec.end(); ++i) {
(a .* (*i))();
}
Я не уверен, что статическое приведение безопасно.