Имя скрывается при изменении как возвращаемого типа, так и списка аргументов

Мой основной вопрос заключается в том, почему скрытие имени не применимо при изменении как возвращаемого типа, так и списка аргументов. Пожалуйста, обратитесь ниже образец образца.

// Example program
#include <iostream>
#include <string>
using namespace std;

class base {
public:
    int f() const { cout <<"I am base void version. "<<endl; return 1;}
    int f(string) const { cout <<"I am base string version. "<<endl; return        1;}
};

class Derived1 : public base {
public:
    int f() const {
        cout << "Derived1::f()\n";
        return 2;
    }
};

class Derived2 : public base {
public:
    int f(int) const {
        cout << "Derived2::f()\n";
        return 3;
    }
};

class Derived3 : public base {
public:
    void f(int) const {
        cout << "Derived3::f()\n";
    }
};


int main()
{
    string s("hello");
    Derived1 d1;
    int x = d1.f();
 //d1.f(s); // string version hidden

   Derived2 d2;
   //x = d2.f(); // f() version hidden
    x = d2.f(1);

    Derived3 d3;
    d3.f(1); // No name hiding
 }

выход:

Derived1::f()

Derived2::f()

Derived3::f()

В вышеуказанной программе

а) Почему строковая версия не скрыта для объекта Derived2?

б) Почему скрытие имени не применимо, когда совпадают и возвращаемый тип, и аргумент?

Любые ссылки или ссылки на "как работает скрытие имен на уровне компилятора?" полезны

Спасибо.

2 ответа

Из собственного FAQ Бьярна Страуструпа на эту тему:

Почему перегрузка не работает для производных классов?

Этот вопрос (во многих вариациях) обычно подсказывается примером, подобным этому:

#include<iostream>
using namespace std;

class B {
public:
  int f(int i) { cout << "f(int): "; return i+1; }
  // ...
};

class D : public B {
public:
  double f(double d) { cout << "f(double): "; return d+1.3; }
  // ...
};

int main()
{
  D* pd = new D;

  cout << pd->f(2) << '\n';
  cout << pd->f(2.3) << '\n';
}

который будет производить:

  f(double): 3.3
  f(double): 3.6

а не

  f(int): 3
  f(double): 3.6

что некоторые люди (ошибочно) догадались.

Вы можете изменить программу в вопросе, чтобы сделать скрытые перегрузки доступными, добавив using base::f; в производный класс:

#include <iostream>
#include <string>
using namespace std;

class base {
public:
    int f() const { cout <<"I am base int version. "<<endl; return 1; }
    int f(string) const { cout <<"I am base string version. "<<endl; return        1; }
};

class Derived1 : public base {
public:
    using base::f;
    int f() const
    {
        cout << "Derived1::f()\n";
        return 2;
    }
};

class Derived2 : public base {
public:
    using base::f;
    int f(int) const 
    {
        cout << "Derived2::f()\n";
        return 3;
    }
};

class Derived3 : public base {
public:

    void f(int) const
    {
        cout << "Derived3::f()\n";
    }
};


int main()
{
    string s("hello");
    Derived1 d1;
    int x = d1.f();
    d1.f(s); // string version hidden

    Derived2 d2;
    x = d2.f(); // f() version hidden
    x = d2.f(1);

    Derived3 d3;
    d3.f(1); // No name hiding
}

Выходные данные тогда:

Derived1::f()
I am base string version.
I am base int version.
Derived2::f()
Derived3::f()

Сокрытие имени- если в производном классе функция-член получает новое определение, есть две возможности

  1. Подпись и тип возврата остаются прежними

    --- Переопределение функций (для обычных функций-членов)

    --- Переопределение функций (для функций виртуальных членов)

  2. Изменение подписи и типа возврата --- Сокрытие имени

    • Если функция получает новое определение в производном классе, все остальные версии автоматически скрываются в производном классе.

    • Перегрузка между областями невозможна

Другие вопросы по тегам