19.5 — Void 指针

void 指针,也称为泛型指针,是一种特殊类型的指针,可以指向任何数据类型的对象!void 指针的声明方式与普通指针相同,使用 void 关键字作为指针的类型。

void* ptr {}; // ptr is a void pointer

void 指针可以指向任何数据类型的对象。

int nValue {};
float fValue {};

struct Something
{
    int n;
    float f;
};

Something sValue {};

void* ptr {};
ptr = &nValue; // valid
ptr = &fValue; // valid
ptr = &sValue; // valid

然而,由于 void 指针不知道它指向的对象类型,因此解引用 void 指针是非法的。相反,void 指针必须首先被转换为另一种指针类型,然后才能执行解引用。

int value{ 5 };
void* voidPtr{ &value };

// std::cout << *voidPtr << '\n'; // illegal: dereference of void pointer

int* intPtr{ static_cast<int*>(voidPtr) }; // however, if we cast our void pointer to an int pointer...

std::cout << *intPtr << '\n'; // then we can dereference the result

这会打印

5

下一个显而易见的问题是:如果 void 指针不知道它指向什么,我们怎么知道要将它转换为哪种类型?最终,这取决于你来跟踪。

这是一个 void 指针的用法示例。

#include <cassert>
#include <iostream>

enum class Type
{
    tInt, // note: we can't use "int" here because it's a keyword, so we'll use "tInt" instead
    tFloat,
    tCString
};

void printValue(void* ptr, Type type)
{
    switch (type)
    {
    case Type::tInt:
        std::cout << *static_cast<int*>(ptr) << '\n'; // cast to int pointer and perform indirection
        break;
    case Type::tFloat:
        std::cout << *static_cast<float*>(ptr) << '\n'; // cast to float pointer and perform indirection
        break;
    case Type::tCString:
        std::cout << static_cast<char*>(ptr) << '\n'; // cast to char pointer (no indirection)
        // std::cout will treat char* as a C-style string
        // if we were to perform indirection through the result, then we'd just print the single char that ptr is pointing to
        break;
    default:
        std::cerr << "printValue(): invalid type provided\n"; 
        assert(false && "type not found");
        break;
    }
}

int main()
{
    int nValue{ 5 };
    float fValue{ 7.5f };
    char szValue[]{ "Mollie" };

    printValue(&nValue, Type::tInt);
    printValue(&fValue, Type::tFloat);
    printValue(szValue, Type::tCString);

    return 0;
}

这个程序打印

5
7.5
Mollie

void 指针杂项

void 指针可以设置为 null 值。

void* ptr{ nullptr }; // ptr is a void pointer that is currently a null pointer

因为 void 指针不知道它指向的对象类型,所以删除 void 指针会导致未定义的行为。如果需要删除 void 指针,请先将其 `static_cast` 回适当的类型。

无法对 void 指针进行指针算术。这是因为指针算术要求指针知道它指向的对象的大小,以便它可以适当地递增或递减指针。

请注意,不存在 void 引用。这是因为 void 引用将是 `void &` 类型,并且不知道它引用的值的类型。

总结

一般来说,除非绝对必要,否则最好避免使用 void 指针,因为它们实际上允许您避免类型检查。这使您可能会无意中做一些没有意义的事情,而编译器不会抱怨。例如,以下是有效的:

    int nValue{ 5 };
    printValue(&nValue, Type::tCString);

但谁知道结果会是什么!

尽管上述函数看起来是一种处理多种数据类型的巧妙方式,但 C++ 实际上提供了一种更好的方法来做同样的事情(通过函数重载),它保留了类型检查以帮助防止误用。许多其他曾经使用 void 指针来处理多种数据类型的地方,现在最好使用模板来完成,模板也提供了强大的类型检查。

然而,偶尔,您可能仍然会发现 void 指针的合理用途。只需确保首先没有更好的(更安全的)方法来使用其他语言机制来做同样的事情!

小测验时间

问题 #1

void 指针和空指针有什么区别?

显示答案

guest
您的电子邮箱地址将不会被显示
发现错误?请在上方留言!
与勘误相关的评论在处理后将被删除,以帮助减少混乱。感谢您帮助使网站对每个人都更好!
来自 https://gravatar.com/ 的头像与您提供的电子邮箱地址相关联。
有回复时通知我:  
176 条评论
最新
最早 最多投票
内联反馈
查看所有评论