C++ наследование и сокрытие имени
Я знаю, что это не первый вопрос по этому вопросу, но все остальные связанные вопросы (и ответы), которые я прочитал, были немного неуместными, по моему мнению. Взять код
#include <iostream>
using namespace std ;
class Base {
public:
void methodA() { cout << "Base.methodA()" << endl ;}
};
class Derived : public Base {
public:
void methodA(int i) { cout << "Derived.methodA(int i)" << endl ;}
};
int main()
{
Derived obj;
obj.methodA();
}
Компиляция этого кода с последней версией g++ выдает ошибку
no matching function for call to 'Derived::methodA()'
Именно из-за этой ошибки я наткнулся на Stackru, чтобы найти ответ. Но ни один из ответов не убедил меня. Сигнатуры двух методов не представляют никакой двусмысленности при их различении, компилятор должен иметь возможность подобрать метод в базовом классе. Просто закомментируйте
class Derived : public Base {
//public:
// void methodA(int i) { cout << "Derived.methodA(int i)" << endl ;}
};
и код работает как положено. Это означает, что это просто имя функции-члена, чтобы скрыть одну и ту же функцию-член имени в базовом классе, и подпись не принимается во внимание, как если бы имена функций не были искажены (в этом случае искажение должно устранить любую неоднозначность). Кто-то еще написал в аналогичном вопросе, что это противоречит духу C++ (и, как я добавил, объектной ориентации), и я полностью согласен с ним. Это ограничение перегрузки функций, для которого я действительно не вижу никакой разумной причины.
Очевидно, вопрос закрыт, поэтому я не могу добавить ответ после прочтения ответов, кроме как путем редактирования моего первоначального вопроса. Я совершенно уверен (но я не в состоянии доказать это), что в старых компиляторах C++ код в моем первоначальном вопросе компилировался (и затем выполнялся) без проблем. Моя точка зрения заключается в том, что я действительно не вижу смысла в выборе языка (как он был назван в ответах). Компилятор, в этом случае, имеет всю информацию, чтобы предпринять правильные действия, и это то, что я ожидаю. В противном случае, похоже, что по выбору дизайна языка он был выбран без учета сигнатуры функций-членов, что звучит довольно странно. Я прочитал статью в "programmerinterview", указанной выше, но она не объясняет, что послужило причиной такого выбора дизайна языка (более того, "someFunction" в "GrandChildClass" в примере кода к концу этой статьи не переопределяет, как уже говорилось, функция-член класса с одинаковым именем: две функции-члена с одинаковыми именами имеют разные сигнатуры - так что это не переопределение).
3 ответа
Так устроен язык - имена во внутренних областях скрывают имена во внешних областях. Здесь производный класс действует как внутренняя область, а базовый класс - как внешняя область.
Тот факт, что функции будут считаться перегрузками, если они находятся в одной области, не имеет значения. Сокрытие работает на имена, а не на отдельные функции.
Вы можете переопределить значение по умолчанию, явно добавив имя к производному классу:
class Derived : public Base {
public:
using Base::methodA; // Now it is visible!
void methodA(int i) { cout << "Derived.methodA(int i)" << endl ;}
};
Это означает, что это просто имя функции-члена, чтобы скрыть ту же функцию-член имени в базовом классе, и подпись не принимается во внимание
Правильный. Именно так был разработан язык. Мне не очень нравится эта особенность языкового дизайна. Но это хорошо задокументировано, и у вас нет выбора.
Я думаю, вы уже поняли. Это называется скрытием имени, и именно так создается язык. Но я не вижу в этом неудобства, так как в конечном итоге вы достаточно комфортно соглашаетесь с этим, когда проводите время с C++. Когда вы определяете не виртуальный метод с тем же именем, что и метод Base, он скрывает метод базового класса в классе Derived, поэтому вы получаете сообщение об ошибке для
obj.methodA();
Чтобы избежать скрытия методов базового класса в классе Derived, вы можете сделать:
obj.Base::methodA();
Для получения дополнительной информации: http://www.programmerinterview.com/index.php/c-cplusplus/c-name-hiding/