Възможно ли е да се определи/твърди, че ако една виртуална функция бъде отменена, друга също е отменена?

Имам съществуващ клас, който декларира виртуален метод и дефинира имплементация по подразбиране. Сега искам да претоваря този метод с диференциален параметър и да дам реализация по подразбиране. Освен това искам да наложа ограничението, че ако първият метод е заменен от подклас, тогава вторият (претоварен) виртуален метод също трябва да бъде заменен.

Това дори възможно ли е в C++? Ако е така, възможно ли е по време на компилиране?

Примерен код:

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)


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

Най-доброто, което можете да направите, е да направите и двете функции чисто виртуални, принуждавайки производния клас да замени и двете. Това най-малкото принуждава автора на производния клас да помисли какво се нуждае от отмяна; невъзможно е да отмените едното и да забравите другото.

Все още можете да предоставите внедряване по подразбиране, така че производните класове, които не искат да заменят нито една от функциите, се нуждаят само от много кратки замени, които извикват версиите по подразбиране.

person Mike Seymour    schedule 13.01.2012

Мисля, че C++ не предоставя никакви средства за откриване на такава липсваща замяна в дете.

@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