Преодолеет ли виртуальный метод Non-Const, скрывает перегрузку Const?

StackOverflow https://stackoverflow.com/questions/4152799

Вопрос

Рассмотреть возможность:

#include <iostream>

using namespace std;

struct A {
  virtual void f() { cout << "A::f" << endl; }
  virtual void f() const { cout << "A::f const" << endl; }
};

struct B : public A {};

struct C : public A {
   virtual void f() { cout << "C::f" << endl; }
};


int main()
{
   const B b;
   b.f();   // prints "A::f const"

   const C c;
   c.f();
   // Compile-time error: passing ‘const C’ as ‘this’ argument of
   //   ‘virtual void C::f()’ discards qualifiers
}

(Я использую GCC.)

Таким образом, кажется, что Const версия F () скрыта в C. Это имеет много смысла для меня, но это обязано стандартом?

Это было полезно?

Решение

Я буду (еще раз) связывать это здорово статья :

Во-первых, [компилятор] смотрит в непосредственной близости, в этом случае объем класса C и делает список всех функций, которые он может найти, которые называются F (независимо от того, доступны ли они или даже принять правильное количество Параметры). Только если это не делает, то продолжайте «наружу» в следующую ограждение [...]

Так да, const версия f скрыто, и это совершенно нормально. Как указано на Симоне, вы можете использовать using Заявление о принести A::f в C объем.

Другие советы

Да это так. Вы можете написать:

struct C : public A {
   virtual void f() { cout << "C::f" << endl; }
   using A::f;       
};

Чтобы сделать ваш код компиляции:

int main()
{
   const B b;
   b.f();   // prints "A::f const"

   const C c;
   c.f();   // prints "A::f const"
}

Для получения дополнительной информации вы можете обратиться к проекту документа C ++ 2010 года (который вы можете найти здесь) Глава 10.2. (3-4).

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

Представьте себе, что ваш код работает (возможно, в течение многих лет), как показано ниже, с неоправданными деталями удалены:

struct Base {
};

struct Derived : Base {
  void f(double);
}

void g(Derived &d) {
  d.f(42);
}

Затем вам нужно изменить базу, чтобы включить метод, который делает что-то совершенно другое, но по какой-то причине вы хотите назвать его «F»:

struct Base {
  void f(int);
};

Без этого правила, каждый Использование полученного вызова F необходимо вручную оценить - и если база в библиотеке, данной другим людям, у вас может даже не иметь доступа к этим другим использованиям! Он становится хуже в лице определенного пользовательских (неявных) преобразований.

Вместо этого было решено потребовать потребовать полученные классы для явного состояния, которые они хотят импортировать указанные имена с базы с использованием декларации. Это правило может быть удивительным, и я не уверен, что это чистая выгода на языке сегодня, но они не спрашивали меня - в то время я мог бы только ответить на них только с двумя слогами слова. :)

Вставлять using B::f;

struct C : public A { 
   using A::f;
   virtual void f() { cout << "C::f" << endl; } 
}; 

C ++ Standard 2003. 13.2 P.1:

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

Таким образом C::f скрывается все A::f.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top