Можно ли определить/утвердить, что при переопределении одной виртуальной функции переопределяется и другая?

У меня есть существующий класс, который объявляет виртуальный метод и определяет реализацию по умолчанию. Теперь я хочу перегрузить этот метод другим параметром, а также дать реализацию по умолчанию. Кроме того, я хочу применить ограничение, согласно которому если первый метод был переопределен подклассом, то второй (перегруженный) виртуальный метод также должен быть переопределен.

Возможно ли это даже внутри С++? Если да, то возможно ли это во время компиляции?

Пример кода:

class ParamA {};
class ParamB {};

class Base
{
public:
    virtual void method(ParamA a)
    {
        // default behavior
    }
    virtual void method(ParamB b)
    {
        // default behavior
    }
}

class Derived : public Base
{
public:
    virutal void method(ParamA)
    {
        // special behavior
    }
}

Моя цель — обнаружить классы типа Derived и заставить их реализовать свою версию method(ParamB b).


person js_    schedule 13.01.2012    source источник
comment
Вы можете сделать обе виртуальные машины в базовом классе чистыми виртуальными...   -  person Fred Foo    schedule 13.01.2012
comment
К сожалению, это не вариант...   -  person js_    schedule 13.01.2012
comment
@js_: Почему это не вариант? Это единственный способ (почти) обеспечить соблюдение правил, которые вы хотите.   -  person Mike Seymour    schedule 13.01.2012
comment
Цель сохранить устаревшее поведение, особенно когда пользователи Base не переопределяют method(Param A). Если сделать оба метода чисто виртуальными, потребуется выполнить много кода и добавить тривиальные переопределения.   -  person js_    schedule 13.01.2012


Ответы (4)


Нет, вы не можете указать сложные ограничения на то, какие наборы функций-членов должны быть переопределены. Единственные ограничения применяются к отдельным функциям; чистый виртуальный (=0) для обязательного переопределения и (в C++11) final для предотвращения переопределения.

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

Вы по-прежнему можете предоставить реализацию по умолчанию, так что производные классы, которые не хотят переопределять ни одну из функций, нуждаются только в очень коротких переопределениях, вызывающих версии по умолчанию.

person Mike Seymour    schedule 13.01.2012

Я думаю, что С++ не предоставляет никаких средств для обнаружения такого отсутствующего переопределения в дочернем элементе.

@larsmans: использование обоих методов в чистом виде приводит к отсутствию реализации по умолчанию.

@js_: не могли бы вы немного рассказать о своей реальной проблеме? То, что вы ищете, кажется мне концептуально не таким ясным.

person boto    schedule 13.01.2012
comment
Синтаксис @ работает только в комментариях, а не в ответах. Ответы предназначены для ответа только на вопрос, а не для предоставления комментариев или вопросов. - person Cody Gray; 13.01.2012
comment
Вы можете предоставить реализацию чистой виртуальной функции по умолчанию. Производные классы должны переопределять его, но они могут свободно вызывать версию по умолчанию, если это желаемое поведение. - person Mike Seymour; 13.01.2012
comment
Коди Грей: Мой ответ (по крайней мере, часть ответа) заключался в том, что C++ не предоставляет такого механизма. Майк: у чистых виртуалов нет тела, или я что-то упустил из виду!? - person boto; 13.01.2012
comment
@boto: Вы что-то упускаете - чистые виртуалы могут иметь тело. Их просто нужно переопределить, поэтому версия по умолчанию может вызываться только статически. Вот пример. - person Mike Seymour; 13.01.2012
comment
@boto: Долгосрочная цель состоит в том, чтобы избавиться от используемого в настоящее время метода (тот, что с ParamA) и заменить его новым методом с использованием нового параметра (поскольку ParamB является обобщением ParamA). Но на данный момент оба параметра должны быть действительными, особенно когда вы выбираете поведение по умолчанию/устаревшее. - person js_; 13.01.2012
comment
@js_: я бы посоветовал вам выбрать имя, отличное от метода, для нового метода, чтобы избежать каких-либо скрытых ошибок или путаницы в вашем коде. На первый взгляд не всегда очевидно, какой метод примет компилятор при вызове, поскольку сигнатура старого метода даже совместима с новой (...поскольку ParamB является обобщением ParamA) - конечно, компилятор примет наиболее подходящая подпись, но это может быть не всегда очевидно для вас как программиста. - person boto; 13.01.2012

Как насчет создания родительского класса, от которого будет наследовать Base? Эти 2 функции будут чисто виртуальными в родительском классе. Производные классы будут наследовать Parent (а не Base) и должны будут реализовать обе функции.

person Igor Oks    schedule 13.01.2012

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

Конечно, вы можете ввести некоторые макросы (например, OVERRIDE_METHODS... Я уверен, вы понимаете, о чем я говорю), но ничто не может помешать пользователям игнорировать их и переопределить только один из указанных методов.

Плюс такие макросы сделают код довольно некрасивым.

person stanson    schedule 13.01.2012