#cpp #qt #gcc #компилятор #стандарт
если в производном классе имеется функция с тем же именем, но различной сигнатурой?
Пример.
Создаем класс TwoStageMap, открыто унаследованного от QMap:
template>
class TwoStageMap : public QMap
{
public:
void insert(const F &fkey, const S &skey, const T &value1); //TODO: return an
iterator of what?
void insert(const QPair &pair, const T &value1);
T value(const F &fkey, const S &skey);
T value(const QPair &pair);
};
При попытки обратиться к value() с сигнатурой из производного класса (TwoStageMap)
все прекрасно работает:
TwoStageMap> tsMap;
tsMap.insert(31, "October", "Halloween");
tsMap.insert(31, "December", "New Year's Eve");
tsMap.insert(25, "December", "Xmas");
tsMap.insert({25, "October"}, "Canna");
qDebug() << "Day1:" << tsMap.value1(31, "December");
, но как только попытаемся вызвать value() самого QMap (чтобы получить внутренний
контейнер под первым ключем), tsMap.value(31);, то тут же получаем ошибку:
no matching member function for call to 'value'
При переименовании функции, например, в value1() проблема исчезает.
Вопрос - это ошибка компилятора или стандарт языка?
Компирятор gcc x86 64bit
Реализация класса, если кто хочет его использовать/попробовать:
template
void TwoStageMap::insert(const F &fkey, const S &skey, const T &value)
{
Cont innerMap;
if (QMap::contains(fkey)) {
innerMap = QMap::value(fkey);
}
innerMap.insert(skey, value);
QMap::insert(fkey, innerMap);
//TODO: return an iterator of what?
}
template
void TwoStageMap::insert(const QPair &pair, const T &value)
{
return insert(pair.first, pair.second, value);
}
template
T TwoStageMap::value(const F &fkey, const S &skey)
{
auto innerMap = QMap::value(fkey);
return innerMap.value(skey);
}
template
T TwoStageMap::value(const QPair &pair)
{
return value1(pair.first, pair.second);
}
PS
В примере Вызов функции_члена шаблонного базового класса из функции производного
шаблонного класса ситуация с невидимостью неквалифицированного имени функции шаблонного
родительского класса, с этим, как раз, вопросов нет, у меня, как можно видеть, идет
обращение через QMap::, здесь же немного другой случай, а именно, вопрос в
том, что мешает компилятору распознать перегружанную функцию с другой сигнатурой, используя
т.н. "искажение имен"? Если это стандарт языка, то вопрос, скорее к Комитету
Ответы
Ответ 1
При вызове метода класса по имени без квалификатора tsMap.value(31); для построения
списка перегрузок будет осуществлен поиск имени без квалификатора в области видимости
класса TwoStageMap согласно спецификации обращения к членам класса:
6.4.5 Class member access [basic.lookup.classref]
2 If the id-expression in a class member access (8.5.1.5) is an unqualified-id,
and the type of the object expression is of a class type C , the unqualified-id is
looked up in the scope of class C.
Этот поиск будет завершен при нахождении имени value в классе TwoStageMap, так как
поиск имени без квалификатора должен завершаться сразу при нахождении первого объявления,
согласно спецификации поиска имени без квалификатора:
6.4.1 Unqualified name lookup [basic.lookup.unqual]
1 In all the cases listed in 6.4.1, the scopes are searched for a declaration in
the order listed in each of the respective categories; name lookup ends as soon as
a declaration is found for the name.
Таким образом метод value из базового класса QMap в списке перегрузок будет отсутствовать.
Чтобы это исправить можно
Внести этот метод в область видимости класса TwoStageMap добавив
using QMap::value;
При вызове использовать имя с квалификатором:
tsMap.QMap::value(31);
Ответ 2
Если я правильно понял проблему, то решается эта проблема с помощью using.
#include
#include
class Base
{
public:
void func(int _v)
{
std::cout << __FUNCTION__ << std::endl;
}
};
class Derived : public Base
{
public:
using Base::func;
void func(const std::string &_str)
{
std::cout << __FUNCTION__ << std::endl;
}
};
int main(int argc, char *argv[])
{
Derived d;
d.func("text");
d.func(1);
return 0;
}
Ответ 3
Не важно какой класс вы напишете. Допустим вы написали такой простой класс:
class Your_class {
protected:
int n{ 3 };
public:
int value(int n) const { return n + 3; }
};
Если я наследую ваш класс, то я наследую все, что не является закрытым членами вашего
класса:
class My_class : public Your_class { };
В таком виде мой класс имеет функцию_член и обьект n вашего класса. Но как только
я добавлю в класс:
class My_class : public Your_class {
public:
bool value(const std::string& s) { return n == s.length(); }
};
Этим я выражаю, что моя value это совсем другая функция(мне не нужен ваш вариант).
И экземпляры моего класса не будут иметь возможность пользоваться одноименной функцией
базового вашего класса. Для обеспечения этой возможности я смогу написать другую функцию,
которая вызовит value вашего класса, или же сделать так, как описан в другом ответе.
Точно также, если я добавляю в класс свой обьект n, то экземпляры моего класса будут
пользоваться только этим обьектом.
Так что, функция=член в производном классе с таким же именем, что и функция_ член
в базовом, не является ее перегрузкой, а является ее заменой