Что такое "структура взлома" и "сокрытие типа/не-типа"?
Я видел это в cppreference.
Поиск по имени в области находит все объявления этого имени, за одним исключением, известным как "взлом структуры" или "сокрытие типа/не-типа": в одной и той же области некоторые вхождения имени могут ссылаться на объявление class/struct/union/enum
, который не является typedef
, в то время как все другие вхождения с одинаковыми именами либо ссылаются на одну и ту же переменную, нестатический член данных (начиная с С++ 14), либо перечислитель, либо все они ссылаются на возможно перегружены имена функций или шаблонов функций
Ссылка на текст выше здесь
Я не понимаю, что такое "структура взломать" и "сокрытие типа/не тип".
Это одна и та же концепция? Можете ли вы дать простое объяснение? Было бы неплохо иметь демонстрацию фрагмента.
Ответы
Ответ 1
В начале был C. В C подобные объявления вполне возможны (и действительно часты):
#include <time.h> // defines struct tm { ... }
struct tm tm;
int stat(const char *pathname, struct stat *statbuf); // defined somewhere in POSIX headers
Этот код является полностью нормальным в C, потому что теги типа tm
или stat
не обозначают типы. Только struct tm
и struct stat
делают.
#include <time.h>
tm my_time; // does not work in C
Введите C++. В C++, если вы определите struct tm { ... };
, тогда tm
- это имя типа.
#include <time.h>
tm my_time; // OK in C++
Но без "одного исключения", описанного в вашей цитате, код C, подобный приведенному выше, не будет компилироваться с помощью компилятора C++.
#include <time.h>
struct tm tm; // would not compile without the exception
// because tm alone already refers to a type
// defined in this scope
Поскольку нарушать совершенно хороший C-код не является целью C++, исключение было изобретено и введено в действие. В основном это говорит о том, что вам разрешено определять переменные, функции и некоторые другие вещи с тем же именем, что и тег class/struct/union. Если вы это сделаете, то один только тег перестает быть именем типа в этой области.
#include <time.h>
struct tm tm; // compiles because of the exception
tm my_time; // no longer compiles because 'tm' variable hides the type
struct tm my_time; // OK
Так что это хак типа "сокрытие типа/нетипов" (потому что тип скрыт не типом) ". Он называется хаком, потому что это небольшой изгиб в совершенно гладком и скучном правиле (" каждое имя относится к одной вещи и только к одной "), что допускает что-то (совместимость со старым кодом C), без которого было бы невозможно. Обычное скрытие имени на основе области действия - это не хак. Это совершенно обычная вещь, а не умный изгиб во всем.
Ответ 2
Предложение действительно следует понимать как:
Исключение, касающееся поиска имен, также относится к "struct hack" с именем "скрытие типа/не типа".
Таким образом, определение концепции, которую вы ищете, на самом деле "скрывает тип/не тип".
Термин "взлом структуры" может сбивать с толку, поскольку он относится к гибкому массиву C, который является специфической реализацией C, а не проблемой поиска имени.
Что касается "сокрытия типа/не-типа", это то, что позволяет вам написать что-то вроде этого и скомпилировать:
#include <iostream>
namespace first
{
class vector
{
public:
int hidden;
};
}
namespace second {
using namespace first;
class vector
{
public:
int visible;
};
double f()
{
vector f;
f.visible=2;
int vector = f.visible;
return vector;
}
};
int main() {
std::cout << second::f() << std::endl;
}
Показать на godbolt.org
Как видите, second::vector
скрывает first::vector
внутри области видимости namespace second
.
Кроме того, внутри f
функция int vector
скрывает second::vector
.
Концепция хорошо объяснена в ветке IBM :
Если имя класса или имя перечисления находится в области видимости и не скрыто, это видимый. Имя класса или имя перечисления может быть скрыто явным объявление того же имени - в качестве объекта, функции или перечислителя - во вложенной декларативной области или производном классе. Имя класса или имя перечисления скрыто, где бы ни находились объект, функция или Имя перечислителя видно. Этот процесс называется именем прячась.
В определении функции-члена скрывается объявление локального имени. объявление члена класса с тем же именем. Объявление члена в производном классе скрывает объявление член базового класса с тем же именем.
Вы также можете проверить стандарт iso cpp:
6.3.10 Сокрытие имени [basic.scope.hiding] или http://eel.is/c++draft/basic.scope.hiding