记录内存地址
如果您想使用 iostreams 输出指针(例如用于日志记录),那么通过 void* 是确保 operator<< 没有以某种疯狂的方式过载的唯一方法。
#include <iostream>
struct foo {
};
std::ostream& operator<<(std::ostream& out, foo*) {
return out<<"it's a trap!";
}
int main() {
foo bar;
foo *ptr = &bar;
std::cout << ptr << std::endl;
std::cout << static_cast<void*>(ptr) << std::endl;
}
测试 iostream 状态
iostreams 重载operator void* 作为状态检查,因此if (stream) 或while (stream) 之类的语法是测试流状态的简便方法。
模板元编程
有时您可能希望将 void* 与模板元编程一起使用,以减少包罗万象,例如使用 SFINAE 技巧,但通常使用一种或另一种形式的部分专业化有更好的方法。
访问大多数派生指针
正如 Alf 在 cmets 中指出的那样,dynamic_cast<void*> 对于在层次结构中获取最多派生类型也很有用,例如:
#include <iostream>
struct other {
virtual void func() = 0;
int c;
};
struct foo {
virtual void func() { std::cout << "foo" << std::endl; }
int a;
};
struct bar : foo, other {
virtual void func() { std::cout << "bar" << std::endl; }
int b;
};
namespace {
void f(foo *ptr) {
ptr->func();
std::cout << ptr << std::endl;
std::cout << dynamic_cast<void*>(ptr) << std::endl;
}
void g(other *ptr) {
ptr->func();
std::cout << ptr << std::endl;
std::cout << dynamic_cast<void*>(ptr) << std::endl;
}
}
int main() {
foo a;
bar b;
f(&a);
f(&b);
g(&b);
}
给予:
foo
0xbfb815f8
0xbfb815f8
bar
0xbfb815e4
0xbfb815e4
bar
0xbfb815ec
0xbfb815e4
在我的系统上。
例外情况
§ 15.3.1 规定:
异常声明不应表示指针或引用
不完整的类型,除了 void*、const void*、volatile void* 或
const volatile void*.
因此,捕获指向不完整类型的指针似乎是唯一合法的方法是通过void*。 (虽然我认为如果你真的需要使用它可能会有更大的问题)
传统 C 使用
void* 有很多“传统”C 用途,用于在不知道数据是什么的情况下存储指向数据的指针,但在新的 C++ 代码中,几乎总是有更好的方式来表达相同的功能。