Мой основной вопрос заключается в том, почему скрытие имени не применимо при изменении как возвращаемого типа, так и списка аргументов. Пожалуйста, обратитесь ниже образец образца.
// 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?
б) Почему скрытие имени не применимо, когда совпадают и возвращаемый тип, и аргумент?
Любые ссылки или ссылки на «как скрытие имен работает на уровне компилятора?» полезны
Спасибо.
От самого Бьярна Страуструпа 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()
Сокрытие имени
— Если в производном классе функция-член получает новое определение, есть две возможности
Подпись и тип возврата остаются прежними
— Функция Redifinition (для обычных функций-членов)
— Переопределение функций (для виртуальных функций-членов)
Подпись и тип возвращаемых изменений
— Сокрытие имени
Если функция получает новое определение в производном классе, все остальные версии автоматически скрываются в производном классе.
Перегрузка между областями невозможна