C ++: проблема наследования - PullRequest
3 голосов
/ 16 апреля 2010

Довольно сложно объяснить, что я пытаюсь сделать, я попробую: представьте себе базу 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;
 }

Как я могу это сделать? Я пробовал два метода:

  1. принудительное приведение из B :: * к A :: *, адаптация указателя для вызова метода типа для объекта другого типа (работает, но кажется плохим);
  2. использование std :: bind + решение выше, безобразный хак;
  3. изменив сигнатуру 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))();
}

Я не уверен, что статическое приведение безопасно.

Ответы [ 5 ]

5 голосов
/ 16 апреля 2010

Самое чистое решение, которое вы предлагаете последним, сделайте test (чистую) виртуальную функцию в A:

virtual bool test(const A& value) = 0;

Если вам надоело сделать somevar публичным, оставьте его закрытым и предоставьте только публичную функцию get:

int getvar() const {return somevar;}
3 голосов
/ 16 апреля 2010

Вы пытаетесь вызвать B и C методы для A. Не делай этого.

Вам необходимо создать фактические экземпляры B и C, сохранить указатели на них в vector<A*> и, во время итерации, вызвать чисто виртуальную test() функцию-член, определенную в A (которая B::test и C::test переопределит).

1 голос
/ 16 апреля 2010

Добавить "virtual bool test () = 0;" в определении А.

Тогда вы можете сделать следующее в вашем цикле:

ret = (ret && i->test());

Кстати: "& =" делает "побитовое и", и вы, вероятно, хотите, чтобы логическое и было выполнено (&&).

Кроме того: экземпляры B и C, на которые вы помещаете указатели в свой вектор, содержат копии унаследованной переменной, все они являются независимыми экземплярами этой переменной.

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

Хотите ли вы запустить множество логических тестов для одной переменной и посмотреть, соответствует ли она всем им? Или каждое противопоказание действительно должно быть проверено на его собственную переменную, и вы хотите получить "логическое" и "все эти независимые тесты?"

0 голосов
/ 16 апреля 2010

Простое решение:

Изменить класс A на:

class A {
public:
    virtual bool test() const = 0;
protected:
    int somevar;
    // ...
};

Теперь мне нужен какой-то контейнер, который позволяет перебирать элементы i этого контейнера, вызывая i :: test () в контексте a.

typedef std::vector<A*> ItemList;
ItemList items;
for(ItemList::const_iterator i = items.begin(); i != items.end(); ++i)
{
    if((*i)->test())
        ; // ???
}

Так что мне интересно, что ОП хочет сделать, но это не ...

0 голосов
/ 16 апреля 2010

Это самое чистое решение на сегодняшний день.Используется static:

struct A {
   int somevar;
};

struct B {
   static bool test(const A& a) {
      return (a.somevar == 42);
   }
};

std::vector<bool (*)(const A&)> vec;

template<typename T>
void push(const T&) {
   vec.push_back(&T::test);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...