C++ Void 指针 教程

本文我们一起看看Void指针,了解它的用法及优缺点。

Void 指针

Void 指针也称为通用指针,可以指向任何类型对象的特殊类型指针。Void 指针声明与正常指针一样,使用void关键字:

void* ptr; // ptr 是Void 指针

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指针不知道指向具体那种类型,直接取值是不允许的。如果需要取值,必须转换为具体类型指针。

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

// std::cout << *voidPtr << '\n'; // 非法: 不允许void指针直接取值

int* intPtr{ static_cast(voidPtr) }; // 但可以转为int类型指针

std::cout << *intPtr << '\n'; // 最后通过int指针取值,输出结果为5

类型转换

如果不知道void指针具体为那种类型,如何进行转换呢?对,你猜对了。我们就在几种可能的类型中猜测:

#include 
#include 

enum class Type
{
    tInt, // 为了避免使用关键字,因此增加前缀t
    tFloat,
    tCString
};

void printValue(void* ptr, Type type)
{
    switch (type)
    {
    case Type::tInt:
        std::cout << *static_cast(ptr) << '\n'; // 转为int指针并取值
        break;
    case Type::tFloat:
        std::cout << *static_cast(ptr) << '\n'; // 转为float指针并取值
        break;
    case Type::tCString:
        std::cout << static_cast(ptr) << '\n'; // 转为char指针,std::cout指定如何处理C风格字符串
        break;
    default:
        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 }; 

尽管一些编译器允许删除指向动态分配内存的void指针,但应该避免这样做,因为这可能导致不确定行为。在void指针上进行指针算术运算是不可能的,这是因为指针算法要知道所指向对象的大小,从而可适当地增加或减少指针。

注意,没有所谓的void引用,这是因为void引用的类型是void &,它并不知道引用的是什么类型的值。

  • void指针的优点
  1. Malloc()和calloc()返回void *类型,这允许这些函数用于分配任何数据类型的内存(只是因为void *)
int main(void)
{
	// Note that malloc() returns void * which can be
	// typecasted to any type like int *, char *, ..
	int *x = malloc(sizeof(int) * n);
}
  1. C中的void指针用于实现C中的泛型函数

一般来说,除非绝对必要,否则避免使用void指针,这样可有效地避免类型检查。请看示例:

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

这里类型参数不对,编译器并不检查,谁知道输出结果会是什么呢! 虽然上面的函数可以处理多个数据类型,但c++实际上提供了一种更好的方法(函数重载),它保留了类型检查,从而避免误用。许多其他地方曾经使用void指针来处理多种数据类型,现在使用模板可以更好地完成,模板也提供了强类型检查。

但在一些偶然的情况下,仍可以看到void指针的合理用途。首先要确保没有更好(更安全)的方法来使用其他机制来做同样的事情!

总结

本文通过示例了解了void指针类型。希望以后遇到能掌握其特性,但不建议太多使用。

你可能感兴趣的:(C&C++,void指针,模板,重载)