Как убедиться, что вы переопределили (скрыли) метод в производном классе на С++?

class Base {

    public:
         void foo() const {
             std::cout << "foo const" << std::endl;
         }

};


class Derived : public Base {

  public:
         void foo()  {
             std::cout << "foo"<< std::endl;
         }


 }

Я хочу убедиться, что константа foo() правильно скрыта для Base. Да, это плохая идея, и, возможно, мне следует сделать Base::foo() const чисто виртуальным, чтобы требовать корректного переопределения Dervied::foo(), но допустим, я не могу сделать Base::foo() const чисто виртуальным . Есть ли лучший способ убедиться, что константа Base::foo() правильно скрыта в Derived?

Изменить: я хочу убедиться, что в Derived я правильно скрыл базовую реализацию.


person kal    schedule 20.05.2009    source источник
comment
Что вы подразумеваете под правильно спрятанным? Либо функция переопределена, либо скрыта. Не может быть обоих.   -  person Johannes Schaub - litb    schedule 20.05.2009
comment
Вы спрашиваете, есть ли способ получить то же поведение, что и ключевое слово переопределения С#? Это превосходное ключевое слово гарантирует, что функция действительно что-то переопределяет. Легко ошибиться, если не переопределить что-то в С++ из-за разницы в сигнатуре функции.   -  person markh44    schedule 20.05.2009
comment
Под скрытым вы имеете в виду не публичное?   -  person zooropa    schedule 21.05.2009
comment
Правильно скрытый относится к тому, что я фактически скрываю реализацию foo Base в Derived. В приведенной выше реализации я на самом деле не скрываю реализацию, так как пропустил стоимость.   -  person kal    schedule 21.05.2009
comment
Тогда это называется переопределением. Вы его в любом случае прячете, если он не виртуальный и имеет такое же имя. Если он виртуальный и вы правильно расставляете подписи, вы переопределяете его, то есть не прячете.   -  person Johannes Schaub - litb    schedule 21.05.2009


Ответы (6)


Просто определив функцию-член foo в производном классе, вы скрыли все функции foo в базовом классе.

Вам нужно будет немного уточнить вопрос — вас беспокоит, что foo в производном классе не является подходящей заменой для foo в базовом классе? Мне трудно понять, о чем вы на самом деле просите.

Редактировать: Судя по вашему редактированию и дополнительным комментариям, я думаю, вы неправильно понимаете, как скрытие работает в C++. В этом случае не имеет значения, что одна функция константная, а другая нет — как только C++ находит функцию foo в производном классе, он перестает искать ее где-либо еще! Обычно это большая ловушка для людей. Рассмотрим следующее:

class Base
{
    void foo(double d)
    {
        cout << d;
    }
};
class Derived : public Base
{
    void foo(int i)
    {
        cout << i;
    }
};

Derived obj;
obj.foo(123.456);

Как вы думаете, что на выходе? Это 123! И вы, вероятно, получили предупреждение компилятора о том, что двойное значение будет усечено. Несмотря на то, что сигнатура функции, которая принимает двойное значение, очевидно, лучше подходит, она никогда не рассматривалась — она была скрыта.

person Mark Ransom    schedule 20.05.2009

"void foo() const" и "void foo()" - это две совершенно разные функции с точки зрения C++. Вот почему вы не видите, что «foo» Производного скрывает «foo» от Базы.

person florin    schedule 20.05.2009
comment
Это неправда, если базовый класс определяет функцию, то он скрывает все функции с тем же именем в базовом классе, даже если они имеют разные параметры (не верите? Попробуйте), способ снова сделать эти функции видимыми использовать с помощью base::foo; - person Motti; 20.05.2009

Вы уверены, что хотите СКРЫТЬ foo() из Base? Если вы хотите использовать полиморфизм, вам нужно сделать базовую версию foo() виртуальной. Однако он не обязательно должен быть чистым. В противном случае вы получите статическую привязку — вы этого хотите?

person TheFogger    schedule 20.05.2009

Если вы не хотите делать его чисто виртуальным и тем самым форсировать реализацию, вы можете просто сделать тело foo() в классе Base и сразу же вызвать исключение. Это служит для того, чтобы заставить любых разработчиков и пользователей реализовать переопределение или заставить его взорваться, когда они попытаются его использовать.

Я видел, как это делается раньше, и хотя это немного уродливо, это определенно работает.

person Paul Sonier    schedule 20.05.2009

Если я правильно понял ваш вопрос, вы спрашиваете, как убедиться, что классы Derived принудительно переопределяют метод, не делая метод чистым в классе Base.

Убедившись, что все ваши производные классы обеспечивают реализацию метода, ИМХО, вы намекаете, что метод в классе Base действительно не используется ни для каких целей. Объекты должны вызывать любую версию класса Derived метода foo(). Следовательно, на мой взгляд, метод должен быть чисто виртуальным. Я не думаю, что каким-либо другим способом добиться этого, я считаю.

Также обратите внимание, что в вашем примере вы изменили подпись foo() в Base и Derived. Это делает метод класса Base невидимым в классе Derived. Если вы не используете using Base::foo, метод foo() не будет виден классу Derived.

person aJ.    schedule 20.05.2009

В Base::foo() вы можете сделать следующее:

assert (dynamic_cast<const Derived*> (this) == NULL);

Но у него есть три проблемы:

  1. Это требует изменения класса Base, который должен быть закрыт для модификации.
  2. Это может быть сильнее, чем вам нужно, поскольку вы можете захотеть разрешить вызов Base::foo() из объекта Base или явно.
  3. Он использует RTTI, что означает vtbl, возможно, поэтому вы не хотите использовать виртуальные функции с самого начала.
person JohnMcG    schedule 20.05.2009