Альтернатива использованию dynamic_cast в C ++ - PullRequest
0 голосов
/ 08 августа 2011

У меня есть эти классы:

class Field{
public:
    int X;

    void validate(){
        validator->validate(this);
    }

    void setValidator(Validator* v){
        validator = v;
    }

private:
    Validator* validator;
};

class DerivedField : public Field{
public:
    int Y;
}

class Validator {
public:
    virtual void validate(Field*); // do something with Field.X
};

class DerivedValidator : public Validator {
    virtual void validate(Field*); //do something with DerivedField.Y
};

Я хочу сделать это:

DerivedValidator* v = new DerivedValidator();
DerivedField* f = new DerivedFiled();
f->setValidator(v);

f->validate(); // Error, Validator::validate called instead of DerivedValidator::validate

Так как это не работает, что я могу сделать, чтобы избежать этого:

class DerivedValidator{
    void validate(Field* f){
        DerivedField* dv = dynamic_cast<DerivedField*>(f);

        // do something with dv.Y
    }
};

Спасибо.

Редактировать: Хорошо, теперь все "ошибки" исправлены.

Ответы [ 5 ]

3 голосов
/ 08 августа 2011

Во-первых, изменив сигнатуру метода, вы создали новый метод, который будет скрывать базовый класс. Вам нужно, чтобы метод DerivedValidator validate () принимал только параметр Field *.

Затем, после того как вы добавили ключевое слово virtual в ваши методы, когда вы передали DerivedField, должен быть вызван правильный метод.

Вы по-прежнему не сможете получить доступ к унаследованным значениям DerivedField, поскольку вы ничего не сказали базовому классу о производном классе. то есть, Field знает все о типах Validator, но не имеет ни малейшего представления, что такое DerivedValidator. Все, к чему вы хотите получить доступ в производном классе, должно пройти через сигнатуру базового класса.

2 голосов
/ 08 августа 2011

Вместо того, чтобы создавать параллельную иерархию классов для полей и валидаторов, вам может быть лучше создать такой дизайн:

class Field{
   public:
   int X;

   virtual bool validate(Validator* v){
      return (v->isValid(X));
   }
}

class DerivedField : public Field{
   public:
   int Y;

   virtual bool validate(Validator* v){
      return (v->isValid(X) && v->isValid(Y));
   }
}

Каждый из ваших производных классов Validator может иметь разные представления о том, что является допустимыма что нет.

2 голосов
/ 08 августа 2011

Хорошо, что это не работает, поскольку DerivedField не наследует от Field. Если вы хотите взломать, вы можете просто использовать приведение в стиле C.

1 голос
/ 08 августа 2011

Ваш код полон мелких ошибок. Во-первых, ваши уроки не происходят ни от чего, я предполагаю, что DerivedField наследуется от Field и DerivedValidator от Validator. Во-вторых, вам нужно написать validator->validate, так как это указатель. В-третьих, у Field::validate нет аргументов, но вы звоните f->validate(v). Если эти ошибки исправлены, то единственное, что вам нужно сделать, это сделать Validator::validate виртуальным и использовать предложенное вами решение (с dynamic_cast).

0 голосов
/ 08 августа 2011

вам нужно сделать Validator :: validate () виртуальным.

...