Как быть уверенным, что метод переопределяет существующий виртуальный в C ++? - PullRequest
2 голосов
/ 07 ноября 2010

Предположим, у нас есть базовый класс, у которого есть виртуальный метод:

class BaseClass
{
    virtual void MethodToOverride() const
    {
        DoSomething();
    }
};

И производный класс, который переопределяет метод (в зависимости от ситуации, мы можем сделать его виртуальным или нет):

class DerivedClass : public BaseClass
{
    void MethodToOverride() const
    {
        DoSomethingElse();
    }
}

Если мы допустим ошибку, например, определив MethodToOverride не константным или с неправильным символом, мы просто определим новый метод, например:

void MethodToOverride() {} // I forgot the const 
void MthodToOverride() const {} // I made a typo

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

Есть ли способ определить функцию как явное переопределение существующей, поэтому компилятор предупреждает меня, если я ее неправильно определила?Что-то вроде (я знаю, что это не существует):

void MethodToOverride() const overrides BaseClass::MethodToOverride() const {} 

Ответы [ 5 ]

6 голосов
/ 07 ноября 2010

Лучший способ состоит в том, чтобы объявить метод чисто виртуальным в BaseClass.

class BaseClass 
{ 
    virtual void MethodToOverride() const = 0;
};

Если реализующие классы наследуются снова (что я бы поставил под сомнение в качестве полу-хорошей практики),нет способа контролировать правильную реализацию.

5 голосов
/ 07 ноября 2010

[[override]] атрибут.Однако он является частью C ++ 0x .

Если вы используете gcc, рассмотрите вариант командной строки -Woverloaded-virtual .

1 голос
/ 07 ноября 2010

C ++ 0x предлагает атрибут для этого (см. Ответ Витау), и, например, Visual C ++ предлагает расширение языка.

Но в портативном C ++ 98 лучшее, что вы можете сделать, - это проверка работоспособности, что базовый класс предлагает доступную функцию-член, которая принимает те же аргументы, как ...

// The following macro is mainly comment-like, but performs such checking as it can.
#define IS_OVERRIDE_OF( memberSpec, args ) \
    suppressUnusedWarning( sizeof( (memberSpec args, 0) ) )

, где

template< typename T >
inline void suppressUnusedWarning( T const& ) {}

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

РЕДАКТИРОВАТЬ Добавлен пример вызова (отказ от ответственности: не тронут руками компилятора):

class BaseClass
{
protected:
    virtual void MethodToOverride() const
    {
        DoSomething();
    }
};

class DerivedClass : public BaseClass
{
protected:
    void MethodToOverride() const
    {
        IS_OVERRIDE_OF( BaseClass::MethodToOverride, () );
        DoSomethingElse();
    }
};

Использование такой проверки работоспособности может улучшить четкость кода в определенных случаях и может спасти вашу задницу в определенных случаях. Это имеет три стоимости. (1) Кто-то еще может принять это за гарантию, а не за информативный комментарий и частичную проверку. (2) функция-член не может быть закрытой в базовом классе, как в вашем примере (хотя это, возможно, положительно). (3) Некоторые люди инстинктивно негативно реагируют на любое использование макросов (они просто запомнили правило о вреде, не понимая его).

Приветствия & hth.,

0 голосов
/ 07 ноября 2010

Вы можете попробовать это::)

#include <iostream>

using namespace std;

class Base
{
    public:
        virtual void YourMethod(int) const = 0;
};

class Intermediate : private Base
{
    public:
        virtual void YourMethod(int i) const
        {
            cout << "Calling from Intermediate : " << i << "\n";
        }
};

class Derived : public Intermediate, private Base
{
    public:
        void YourMethod(int i) const
        {
            //Default implementation
            Intermediate::YourMethod(i);

            cout << "Calling from Derived : " << i << "\n";
        }
};

int main()
{
    Intermediate* pInterface = new Derived;
    pInterface->YourMethod(10);
}

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

0 голосов
/ 07 ноября 2010

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

Например:

class BaseClass
{
    virtual void MethodToOverride() const = 0;
    //let's not forget the destructor should be virtual as well! 
};

inline void BaseClass::MethodToVerride const()
{
    DoSomething();
}
//note that according to the current standard, for some inexplicable reasons the definition
//of a pure virtual function cannot appear 'inline' in the class, only outside

Если вы не можете позволить, чтобы ваш базовый класс был абстрактным, то C ++ 03 дает мало, и ответ @ vitautдает то, что вам нужно для C ++ 0x.

В вашем вопросе было предложение, которое встревожило меня.Вы говорите, что можете сделать метод дальше виртуальным или нет.Ну, вы не можете, в C ++ 03.Если метод был объявлен виртуальным, он будет виртуальным во всей иерархии, независимо от того, указали вы его явно или нет.EG

class A
{
    virtual void f(){}
} ;
class B: public A
{
   void f(); //same as virtual void f();
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...