Полиморфизм и проверка наличия у объекта определенного метода-члена - PullRequest
0 голосов
/ 16 августа 2010

Я разрабатываю библиотеку графического интерфейса с другом, и мы столкнулись с проблемой того, как определить, должен ли определенный элемент быть активируемым или нет (или подвижным, и т. Д.).

Мы решили простопроверьте, существует ли функция для определенного объекта, все элементы графического интерфейса хранятся в векторе с указателями на базовый класс.

Так, например, если у меня есть

class Base {};
class Derived : public Base
{
    void example() {}
}
vector<Base*> objects;

Как бы я проверитьесли у члена объектов есть функция с именем example.

Если это невозможно, чем можно было бы по-другому реализовать необязательное поведение, такое как нажатие и подобное.

Ответы [ 5 ]

8 голосов
/ 16 августа 2010

Вы можете просто использовать виртуальный метод IsClickable() в своем базовом классе:

class Widget {
public:
    virtual bool IsClickable(void) { return false; }
};
class ClickableWidget : public Widget
{
public:
    virtual bool IsClickable(void) { return true; }
}
class SometimesClickableWidget : public Widget
{
public:
    virtual bool IsClickable(void); 
    // More complex logic punted to .cc file.
}
vector<Base*> objects;

Таким образом, объекты по умолчанию не активируются. Кликабельный объект переопределяет IsClickable() или подклассы ClickableWidget вместо Widget. Не нужно сложного метапрограммирования.

РЕДАКТИРОВАТЬ: Чтобы определить, можно ли что-то нажимать:

if(object->IsClickable()) {
   // Hey, it's clickable!
}
4 голосов
/ 16 августа 2010

Лучший способ сделать это - использовать множественное наследование, то есть интерфейсы.

class HasExample // note no superclass here!
{
    virtual void example() = 0;
};

class Derived : public Base, public HasExample
{
    void example()
    {
        printf("example!\n");
    }
}

vector<Base*> objects;
objects.push_back(new Derived());

Base* p = objects[0];
HasExample* he = dynamic_cast<HasExample*>(p);
if (he)
    he->example();

dynamic_class <> () во время выполнения проверяет, реализует ли данный объект HasExample, и возвращает либо HasExample* или NULL.Однако, если вы обнаружите, что используете HasExample *, это, как правило, знак того, что вам нужно переосмыслить свой дизайн.

Осторожно!При таком множественном наследовании (HasExample *) ptr! = Ptr.Приведение указателя к одному из его родителей может привести к изменению значения указателя.Это совершенно нормально, и внутри метода это будет то, что вы ожидаете, но это может вызвать проблемы, если вы не знаете об этом.

Редактировать: Добавлен пример dynamic_cast <>(), потому что синтаксис странный.

1 голос
/ 16 августа 2010

Если вы готовы использовать RTTI.,.

Вместо проверки имен классов вы должны создать Clickable, Movable и т. Д.Затем вы можете использовать dynamic_cast, чтобы увидеть, реализуют ли различные элементы интерфейс, который вас интересует.

У IBM есть краткий пример программы, иллюстрирующий dynamic_cast здесь .

1 голос
/ 16 августа 2010

Я бы создал интерфейс, сделал бы метод (ы) частью интерфейса, а затем внедрил бы этот Интерфейс для любого класса, который должен иметь функциональность.

Это имеет смысл при попытке определить, реализует ли Объект некоторый набор функций (вместо проверки имени метода):

class IMoveable
{
    public:
        virtual ~IMoveable() {}
        virtual void Move() = 0;
};

class Base {};

class Derived : public Base, public IMoveable
{
    public:
        virtual void Move()
        {
            // Implementation
        }
}

Теперь вы больше не проверяете имена методов, а приводите к типу IMoveable и вызываете Move ().

0 голосов
/ 16 августа 2010

Я не уверен, что это легко или хорошо сделать это с помощью размышлений. Я думаю, что лучшим способом было бы иметь интерфейс (например, GUIElement) с функцией isClickable. Сделайте так, чтобы ваши элементы реализовывали интерфейс, и тогда те, которые активируются кликом, вернут true в своей реализации функции. Все остальные, конечно, вернут ложь. Если вы хотите узнать, можно ли что-то нажимать, просто вызовите функцию isClickable. Таким образом, во время выполнения вы можете изменить элементы, чтобы они стали активными, если вы не нажимаете на них - если это имеет смысл в вашем контексте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...