Как заставить дочернюю виртуальную функцию сначала вызывать родительскую виртуальную функцию - PullRequest
4 голосов
/ 13 апреля 2011

ребята, У меня есть случай, когда требуется, чтобы дочерний класс сначала вызвал свою родительскую виртуальную функцию перед вызовом виртуальной функции переопределения.

BaseClass::Draw()
{

}

ChildClass::Draw()
{
    BaseClass::Draw(); // BaseClass Draw must be called first.
}

GrandChildClass::Draw()
{
    ChildClass::Draw(); // ChildClass Draw must be called first.
}

Я хочу скрыть это поведение от клиентов. На этом есть шаблон?

Спасибо.

1 Ответ

16 голосов
/ 13 апреля 2011

Для простых случаев вы можете использовать вторую закрытую функцию-член для переопределяемого поведения:

class Base {
public:
    void Draw() { 
        // Base-class functionality here
        OverrideableDraw();
    }

private:
    virtual void OverrideableDraw() { }
};

class Derived : public Base {
private:
    virtual void OverrideableDraw() {
        // Derived-class functionality here
    }
};

Для более сложных иерархий (например, когда у вас есть несколько уровней наследования), это невозможно, поскольку любой производный класс может переопределить любую виртуальную функцию-член (в C ++ нет final). Обычно можно предположить, что каждый производный класс делает правильные вещи. Хотя я могу несколько раз подумать, что у меня возникли проблемы, потому что производный класс облажался с переопределением, эти случаи обычно довольно просто отлаживать.

Если вы действительно беспокоитесь об этом и действительно хотите гарантировать, что переопределения базового класса выполняются первыми, вы можете использовать что-то вроде этого, хотя это довольно дорого (по крайней мере, эта наивная реализация довольно дорога):

#include <functional>
#include <iostream>
#include <vector>

class Base {
public:

    Base() {
        RegisterDrawCallback(std::bind(&Base::DrawCallback, this));
    }

    void Draw() {
        for (auto it(drawCallbacks_.begin()); it != drawCallbacks_.end(); ++it)
            (*it)();
    }

protected:

    typedef std::function<void(void)> DrawCallbackType;
    typedef std::vector<DrawCallbackType> DrawSequence;

    void RegisterDrawCallback(DrawCallbackType f) {
        drawCallbacks_.push_back(f);
    }

private:

    void DrawCallback() { std::cout << "Base" << std::endl; }

    DrawSequence drawCallbacks_;
};

class Derived : public Base {
public:

    Derived() {
        RegisterDrawCallback(std::bind(&Derived::DrawCallback, this));
    }

private:

    void DrawCallback() { std::cout << "Derived" << std::endl; }
};

class DerivedDerived : public Derived {
public:

    DerivedDerived() {
        RegisterDrawCallback(std::bind(&DerivedDerived::DrawCallback, this));
    }

private:

    void DrawCallback() { std::cout << "DerivedDerived" << std::endl; }
};

[Это всего лишь один вариант; кто-то другой может, вероятно, придумать гораздо более элегантное решение. Лично я бы просто позаботился о том, чтобы функции виртуальных членов были хорошо документированы, и оставил все как есть.]

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