Можете ли вы скрыть виртуальный метод в C ++? - PullRequest
4 голосов
/ 01 декабря 2009

У меня есть базовый класс с виртуальной функцией.

virtual CString& Foo();

Я хочу перегрузить это в подклассе, вот так

CString Foo();

есть ли способ скрыть виртуальную функцию базовых классов? Что-то вроде нового ключевого слова в vb.net или C #

Ответы [ 6 ]

16 голосов
/ 01 декабря 2009

Зачем кому-то делать что-то подобное? Это нарушает контракт базового класса. Если вы не хотите реализовывать подкласс, который имеет тот же интерфейс, что и базовый класс, почему вы вообще наследуете? Используйте композицию.

В C ++ нет эквивалента ключевому слову C # new . Таким образом, вы не можете отменить «виртуальность» метода.

Если вы действительно хотите сделать это, вы всегда можете:

  • переопределить метод в подклассе как приватный.

  • создать перегрузку. Но перегрузка должна иметь разные параметры .

Но если вы это сделаете, ИМХО что-то не так с вашим дизайном. Мне бы хотелось, чтобы каждый компилятор C ++ воспринимал обе эти ситуации как минимум как предупреждения.

9 голосов
/ 02 декабря 2009

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

struct base {
   virtual std::string const & f() { 
      static std::string s = "virtual"; 
      return s; 
   }
};
namespace detail {
   class place_holder; // no need to define it, it is just a place holder (duh)
}
struct derived : public base {
   std::string f( place_holder* p = 0 ) { return "crooked"; }
};
int main() {
   derived d; std::cout << d.f() << std::endl; // crooked
   base& b = d; std::cout << b.f() << std::endl; // virtual
}

Хитрость в том, что, определяя метод с тем же именем и разными аргументами в производном классе, вы фактически скрываете базовый класс (если вы не добавите using base::f в производный класс, но тогда вызов будет неоднозначным) , В то же время, поскольку единственный добавленный аргумент имеет значение по умолчанию, вы можете вызывать его без аргументов, и компилятор добавит аргумент по умолчанию для вас.

Обратите внимание, что вы на самом деле не удаляете метод из объекта, а скорее скрываете его в производном классе. Если метод вызывается через указатель или ссылку на базовый класс, виртуальный метод все еще существует и будет вызван.

1 голос
/ 21 мая 2011

технически вы можете объявить метод в производном классе static:

static CString& Derived::foo()

это звучит странно, но попробуйте - компилятор сядет и выдаст предупреждение. Переопределение будет игнорироваться, а virtual Base::foo() будет скрыто и заменено статическим Derived::foo().

Зачем тебе что-то подобное?

1 голос
/ 05 августа 2010
  1. ваш код не скомпилируется. Полагаю, вы это знаете, поэтому вы задали вопрос здесь.
  2. однако ваша задача - просто скрыть виртуальную функцию базового класса. Для этого создайте другую функцию с некоторыми другими аргументами, чем функция базового класса. Это скроет функцию базового класса.
1 голос
/ 01 декабря 2009

Сначала вы не можете переопределить

virtual CString& Foo()

с

CString Foo()

, так как они отличаются только типом возвращаемого значения - это не скомпилируется.

Если функция с подписью

int foo();

равно virtual в базовом классе - функции с одинаковой сигнатурой в производных классах также будут виртуальными; вам не нужно указывать virtual в производных классах.

Дополнительную информацию о виртуальных функциях (и даже больше!) Вы можете найти на C ++ FAQ Lite .

0 голосов
/ 01 декабря 2009

Нет, не совсем. Даже если вы введете промежуточный класс для создания унаследованного метода private, это не поможет, так как закрытые виртуальные методы все еще могут быть переопределены в C ++.

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