Мой вопрос прост: Что такое пустые указатели для в C++? (Те вещи Вы объявляете с void* myptr;
)
Каково их использование? Я могу заставить их указать на переменную какого-либо типа?
void ptr - это, по сути, пустое поле. Заполните его чем хотите, но убедитесь, что вы пометили его (преобразование)
То, что вы могли бы делать на C с помощью void, но не может в C ++:
void * автоматически преобразуются в другие типы указателей. (Вы знаете , что это void * - вы не получаете никакой безопасности типа от принудительного явного приведения)
Struct* p = malloc( sizeof(Struct) );
// vs C++
Struct* p = (Struct*)malloc( sizeof(Struct) );
// Some will argue that that cast style is deprecated too, and c++ programmers
// need to actually do this:
Struct* p = reinterpret_cast<Struct*>malloc( sizeof(Struct) );
// See what C++ did there? By making you write Struct a 3rd time, you can now be sure
// you know what you are doing!
void * также выполнял подсчет косвенных ссылок в C, обеспечивая большую безопасность при передаче указателей на функции, которые принимают указатель на указатель.
void funcInitializingOutPtr( void** ppOut)
{
*ppOut = malloc( x );
}
int* out = NULL;
funcInitializingPtr(out); // C would signal this as an error
funcInitializingPtr(&out); // correct
// vs C++
funcInitializingPtr( (void**)&out ); // so much safer needing that exlicit cast.
funcInitializingPtr( (void**)out); // oops. thanks C++ for hiding the common error
По сути, это пережиток C.
Каково их применение?
В C они широко использовались и используются, но в C++, я думаю, они нужны очень редко, если вообще нужны, поскольку у нас есть полиморфизм, шаблоны и т.д., которые обеспечивают гораздо более чистый и безопасный способ решения тех же проблем, где в C использовались бы указатели void.
Могу ли я сделать так, чтобы они указывали на переменную любого типа?
Да. Однако, как отмечали другие, вы не можете использовать указатель void напрямую - сначала вы должны привести его к указателю на конкретный тип данных.
Да, это конструкция C (не специфичная для C ++), которая позволяет объявлять переменную-указатель, указывающую на любой тип. С таким указателем ничего нельзя сделать, кроме как вернуть его к реальному объекту, на который он фактически указывает. В современном C ++ void * в значительной степени вышел из моды, уступая во многих случаях общему коду на основе шаблонов.
От cplusplus.com:
Тип указателя void является специальным тип указателя. В C++, void представляет собой отсутствие типа, поэтому указатели void - это указатели, которые указывают на значение, которое не имеет типа (и, следовательно. также неопределенную длину и неопределенная длина и неопределенные свойства разыменования).
Это позволяет указателям пустоты указывать на любой тип данных, от целочисленного значения или поплавка до строки символов. Но взамен они имеют большое ограничение: данные, на которые они указывают не могут быть непосредственно разыменованы (что логично, поскольку у нас нет типа для разыменовывать), и по этой причине нам всегда придется приводить адрес в указателе void к некоторому другой тип указателя, который указывает на конкретный тип данных, прежде чем разыменовывать его.
Однажды они в C выполнили задание быть указателем на что угодно, указателем, который вы передали библиотекам, а они вернули вам как пользовательские данные. Пустота * вообще бесполезна без того, чтобы программист каким-либо образом знал их контекст, поскольку вы не знаете, что находится на другом конце, вы ничего не можете сделать с данными. За исключением того, что передайте указатель на другой код, который знает.
Я не понимаю, почему люди не использовали просто неопределенные типы, то есть непрозрачные указатели. Типовая безопасность, пользовательские данные.
В современном C ++ указатель на пустоту почти полностью заменен полиморфизмом и генерируемым шаблоном универсальным кодом. Однако вам все равно, возможно, придется использовать их для взаимодействия с собственным кодом C. Чтобы безопасно использовать void * в любом данном контексте, приводите только один тип к void *. Таким образом, вы точно знаете, на что он указывает. Если вам нужно больше типов, вы можете быстро создать
struct safevoidptr {
base * ptr
};
или
struct safevoidptr {void * ptr; тип int; };
Я считаю, что dynamic_cast также может преобразовывать void * в полиморфные типы, хотя я никогда не использовал dynamic_cast, поэтому не верьте мне на слово.
Указатель на void
является наиболее близкой концепцией к указателю языка ассемблера. Это общий указатель, который резервирует место для адреса или местоположения чего-либо (функции или данных). Как заявляли другие, он должен быть приведен, прежде чем его можно будет разыменовать.
Указатель void
- популярный инструмент для представления концепций объектно-ориентированного программирования на языке C. Одна проблема с указателем void заключается в том, что содержимое может не соответствовать восприятию получателя. Если вызывающий устанавливает указатель так, чтобы он указывал на квадрат, но принимающая функция ожидает указатель на кота, с приведением указателя будут происходить неопределенные и странные вещи.
Поскольку существует уже так много хороших ответов, я бы просто предоставил один из наиболее распространенных, которые я видел: специализация шаблонов. Если я не помню ошибочно, в книге Страуструпа есть пример этого: специализация вектора как вектора, а затем получение вектора (частным образом) из вектора. Таким образом, вектор будет содержать только простые, легко встроенные коды (т.е. вызов соответствующих функций из вектора). Это уменьшит количество дублирований, когда вектор компилируется в программе, которая использует его с множеством разных типов указателей.
Я использую их в своих динамических списках для хранения большего количества типов объектов (все они являются указателями).
typedef void* Object;
Затем, когда вы объявляете переменную Object, вы можете хранить в ней любой указатель.
Это более или менее полезно в зависимости от потребностей.
Я нахожу его очень полезным, когда вам нужно где-то хранить указатель, и вы не можете просто вывести все ваши классы из одного. В остальных случаях, как сказали другие, лучше использовать шаблоны, полиморфизм и т.д.
Примерно одним из немногих вариантов использования указателей void в C ++ является их использование для перегрузки операторов new
. Все операторы new
по определению возвращают тип void *
. В остальном то, что говорили другие, правда.
Я полагаю, что void * - это место в памяти, где вы можете привести / сохранить что угодно. Некоторые эксперты по языку не согласятся со мной в этом вопросе. но я успешно использовал его во многих своих проектах.
Единственная проблема, которую я вижу, - это безопасность типов
Указатель void может указывать на что угодно, если только его память: -)
Стандарт C утверждает, что вы можете преобразовать любой указатель в указатель void, а затем вернуть его обратно без потерять что-нибудь.
Скрытие типа. Он все еще имеет свое допустимое применение в современном C ++. Покопайтесь в исходном коде в ускоренном темпе, и вы найдете несколько. Как правило, использование пустоты * зарыто очень глубоко в недрах более сложной конструкции, которая обеспечивает безопасность типов интерфейса при выполнении черной и злой магии внутри.