1.什么是void*
首先void*中的void代表一个任意的数据类型,"星号"代表一个指针,所以其就是一个任意数据类型的指针。
其实就是一个未指定跳跃力的指针。
那void*的跳跃力又什么时候指定?在需要使用的时候指定就可以了,好处:可以实现泛型编程,节省代码。
对于指定数据类型的指针如int* ,double*等,他们的sizeof都是4个字节,因为都是一个指针,只是指针指向的数据类型不一致。
2.void*使用场景
2.1:当函数传参是个指针时,不确定数据类型时或者支持多种数据类型传递时。
2.2:函数返回值不需要考虑类型,只关心返回的大小。
3.void*使用中的注意点:
1.使用赋值运算符“=”时,void*只能作为左值不能作为右值。
void*作为一个未指定数据类型的指针,可以指向任何一个数据类型的指针,但是有数据类型的指针,不能指向一个void* 的指针。
int i = 5;
int* pi = &i;
void* pv = pi;
int* pi1 = pv;//编译错误,void*类型的指针不能初始化为指定类型的指针
2.void*类型必须强转为指定类型的数据才能使用。
void*在未指定类型的情况下,是不能直接使用的,只有在转换为显示类型后才能使用。
void*一定要强转为具体指针类型后才能使用. 没有强转的void*是没有意义的。
int i = 5;
int* pi = &i;
void* pv = pi;
//cout << *pv << endl;//表达式必须是指向完整对象类型的指针
int* pip = (int*)pv;
cout << " *pip="<<*pip << endl; // *pip=5
3. 使用(void*)0表示空指针。
在C语言中空指针定义方式:
在C语言中NULL代表(void*)0,
#define NULL ((void*)0)
在C++语言中:
在C++中NULL代表的是0,使用nullptr来表示(void*)0空指针,
所以在C++中推荐使用新标准的nullptr来初始化一个空指针。
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif
#endif
4.当void*作为函数的参数类型或者返回值类型时,说明该函数可以接收或者返回任意类型的指针。
/*
void* pVoid 可以使用任意类型的实参指针类型
返回值也可以返回任意类型的指针
// 但是 niubiMeth()函数返回值 最终需要转换为具体类型指针才能使用。
*/
void* niubiMeth(void* pVoid) {
return pVoid;
}
double dou = 11.11;
double* dp = &dou;
// 但是 niubiMeth()函数返回值 最终需要转换为具体类型指针才能使用。
double* resultPDou = static_cast<double *>(niubiMeth(dp));
double resultDou = *resultPDou;
cout << "返回的结果 resultPDou ="<<resultPDou<<" 对应的数值resultDou ="<<resultDou << endl;
// 返回的结果 resultPDou =0x99fec0 对应的数值resultDou =11.11
void*在C++中的作用其实就是为了实现泛型编程,和Java中使用Object来表示是一样的,所以又称为通用指针和泛指针,不过C++中大部分情况下会使用模板编程来实现泛型。
//C++中大部分情况下会使用模板编程来实现泛型。
template<typename T>
T _say(T t) {
return t;
}
int main(){
/*
模板编程不需要将强制转换为具体类型
未强转也可以直接得出结果,这是因为模板编程会在编译器帮我们生成具体的函数。
T _say(T t) {return t;} -> int* _say(int* t) {return t;}
*/
int i = 5;
int* pi = &i;
int* resultPI = _say(pi);
cout << " *resultPI="<<*resultPI<< endl; // *resultPI=5
float ff = 10.8;
float* pff = &ff;
float* resultPff = _say(pff);
cout << " *resultPff ="<<*resultPff<< endl; // *resultPff =10.8
}
总结
1.void*是一个过渡型的指针状态,可以代表任意类型的指针,取值的时候需要转换为具体类型才能取值。其是处于数据类型顶端的状态:
2.void* 使用赋值运算符“=”赋值时,只能将具体类型赋值给void星,不能将void*赋值给具体类型。
3.void*一般作为参数或者返回值来实现泛型编程,但是C++中一般考虑使用模板编程来实现。
#include <iostream>
using namespace std;
void say(int type, void* pVoid) {
switch(type){
case 0:{
int* pInt = static_cast<int *>(pVoid);
cout << "转为int类型的指针 pInt=" <<pInt <<" 对应的数值 *pInt="<<*pInt<< endl; //转为int类型的指针 pInt=0x99ff1c 对应的数值 *pInt=9527
break;
}
case 1:{
float* pFloat = static_cast<float *>(pVoid);
cout << "转为float类型的指针 pFloat=" <<pFloat <<" 对应的数值 *pFloat="<<*pFloat<< endl; //转为float类型的指针 pFloat=0x99ff10 对应的数值 *pFloat=23.3333
break;
}
case 2:{
double* pDouble = static_cast<double *>(pVoid);
cout << "转为double类型的指针 pDouble=" <<pDouble <<" 对应的数值 *pDouble="<<*pDouble<< endl; //转为double类型的指针 pDouble=0x99ff10 对应的数值 *pDouble=9527.54
break;
}
}
};
int say2( void* pVoid){
int* pInt = static_cast<int *>(pVoid);
cout << "转为int类型的指针 pInt=" <<pInt <<" 对应的数值 *pInt="<<*pInt<< endl;
//转为int类型的指针 pInt=0x99ff1c 对应的数值 *pInt=9527
return *pInt-7;
}
float say22( void* pVoid){
float* pFloat = static_cast<float *>(pVoid);
cout << "转为float类型的指针 pFloat=" <<pFloat <<" 对应的数值 *pFloat="<<*pFloat<< endl;
//转为float类型的指针 pFloat=0x99ff10 对应的数值 *pFloat=23.3333
return *pFloat+10;
}
void* say3(int type, void* pVoid) {
switch(type){
case 0:{
int* pInt = static_cast<int *>(pVoid);
cout << "转为int类型的指针 pInt=" <<pInt <<" 对应的数值 *pInt="<<*pInt<< endl; //转为int类型的指针 pInt=0x99ff1c 对应的数值 *pInt=9527
return (void*)pInt;
break;
}
case 1:{
float* pFloat = static_cast<float *>(pVoid);
cout << "转为float类型的指针 pFloat=" <<pFloat <<" 对应的数值 *pFloat="<<*pFloat<< endl; //转为float类型的指针 pFloat=0x99ff10 对应的数值 *pFloat=23.3333
return (void*)pFloat;
break;
}
case 2:{
double* pDouble = static_cast<double *>(pVoid);
cout << "转为double类型的指针 pDouble=" <<pDouble <<" 对应的数值 *pDouble="<<*pDouble<< endl; //转为double类型的指针 pDouble=0x99ff10 对应的数值 *pDouble=9527.54
return (void*)pDouble;
break;
}
}
}
/*
void* pVoid 可以使用任意类型的实参指针类型
返回值也可以返回任意类型的指针
// 但是 niubiMeth()函数返回值 最终需要转换为具体类型指针才能使用。
*/
void* niubiMeth(void* pVoid) {
return pVoid;
}
//C++中大部分情况下会使用模板编程来实现泛型。
template<typename T>
T _say(T t) {
return t;
}
int main(){
int number = 9527;
say(0,&number);
int resultInt = say2(&number);
cout << "返回的结果 resultInt="<<resultInt<< endl; //返回的结果 resultInt=9520
int* resultPInt = static_cast<int *>(say3(0, &number));
cout << "返回的结果 resultPInt="<<resultPInt<<" 对应的数值*resultPInt="<< *resultPInt << endl; //返回的结果 resultPInt=0x99ff00 对应的数值*resultPInt=9527
float f = 70.0/3.0;
say(1,&f);
float resultFloat = say22(&f);
cout << "返回的结果 resultFloat="<<resultFloat<< endl; //返回的结果 resultFloat=33.3333
float * resultPFloat = static_cast<float *>(say3(1, &f));
cout << "返回的结果 resultPFloat ="<<resultPFloat<<" 对应的数值*resultPFloat="<< *resultPFloat << endl; //返回的结果 resultPFloat =0x99fef8 对应的数值*resultPFloat=23.3333
double d = 9527.54;
say(2,&d);
double* resultPDouble = static_cast<double *>(say3(2, &d));
cout << "返回的结果 resultPDouble ="<<resultPDouble<<" 对应的数值*resultPDouble="<< *resultPDouble << endl; //返回的结果 resultPDou =0x99fed8 对应的数值*resultPDou=11.11
double dou = 11.11;
double* dp = &dou;
// 但是 niubiMeth()函数返回值 最终需要转换为具体类型指针才能使用。
double* resultPDou = static_cast<double *>(niubiMeth(dp));
double resultDou = *resultPDou;
cout << "返回的结果 resultPDou ="<<resultPDou<<" 对应的数值resultDou ="<<resultDou << endl;
// 返回的结果 resultPDou =0x99fec0 对应的数值resultDou =11.11
int i = 5;
int* pi = &i;
void* pv = pi;
//cout << *pv << endl;//表达式必须是指向完整对象类型的指针
int* pip = (int*)pv;
cout << " *pip="<<*pip << endl; // *pip=5
/*
模板编程不需要将强制转换为具体类型
未强转也可以直接得出结果,这是因为模板编程会在编译器帮我们生成具体的函数。
T _say(T t) {return t;} ->
int* _say(int* t) {return t;}
float* _say(float* t) {return t; }
*/
int* resultPI = _say(pi);
cout << " *resultPI="<<*resultPI<< endl; // *resultPI=5
float ff = 10.8;
float* pff = &ff;
float* resultPff = _say(pff);
cout << " *resultPff ="<<*resultPff<< endl; // *resultPff =10.8
return 0;
}