C++中的void类型

简介:

1.1. void类型

void类型其实是一种用于语法性的类型,而不是数据类型,主要用于作为函数的参数或返回值,或者定义void指针,表示一种未知类型。

1.1.1. 作为函数参数与返回值

void func( void );

void func( );

例如上面两例,其实两种声明方式是等效的,在C++中如果参数列表为空,默认的参数类型即为void,但建议没有参数时使用void以提高程序的可读性。

因 为C++在定义函数时不允许返回值类型为空,在C++98之前,是允许定义函数时不定义返回值的,默认的返回值是int类型。其实默认int类型并不是好 事,如果函数有返回值在函数返回时是需要消耗CPU传递返回值的,也或许也是C++98标准将默认返回值类型改为void的原因。

因为C++不允许默认返回值,所以当函数不需要返回值是,需要将返回值类型声明为int类型。当调用返回值类型为void类型的函数时,在工程上有很多实际代码在前面加上(void)类型转换,以提高代码的可读性。如调用上面定义的 func函数。

(void)func( );

从另一个角度讲,这样严谨的方式是可以提高软件的健壮性的,调用函数时可以明确地看出是没有返回值的,如果调用一个返回值不是int类型的函数时最好判断其返回值,以检查函数调用是否成功,如:

#include

char buff[5];

func( );

snprintf(buff, sizeof(buff), “%d”, “10240”);

显 然这段代码是有问题的,当然func没有返回值,这样调用是没有问题,但snprintf的调用会有问题因为缓冲区有可能太小而不能容纳结果字符串,上面 的代码就有这个问题。假设我们不知道snprintf有没有返回值,可能这个BUG我们不会发现,直到有一天出现了我们不期望的结果。如果我们严格要求调 用每个函数时必须判断函数的返回值,按照以下面的代码编码,就不会出给我们的程序造成隐患。

#include

#include

char buff[5];

(void)func( );

if( sizeof(buff) <= snprintf(buff, sizeof(buff), "%d", 10240) ){

buff[sizeof(buff) - 1] = '/0';

throw std::overflow_error("buff overflow");

}

1.1.2. void指针

void* pv = NULL;

string str = "string";

int i = 1;

pv = &str;

pv = &i;

int *pi = (int*)pv;

string* ps = (string*)pv;

如 上面的示例所示,void指针表示未知类型的指针,可以将任意类型的指针直接赋值给void指针,好比是C#、Java中的object引用,可以把任意 类型的对象赋值给它。但把void类型赋值给特定类型的指针时,就需要进行强制转换,因为C++为类型语言,尽可能保证类型安全,如果使用了强制类型转 换,编译器就认为程序员知道他(她)在干什么,程序也应该负起这样做的责任。

值得注意的是,函数指针与类成员的指针不能赋值给void*类型变量。

void* 在C语言中一般用于动态内存的操作,因为malloc和calloc返回的类型都是void*类型。在W3C的协议库libwww里,大量使用了 void*类型,如果使用C++的继承特性的话,应该会使代码可读性更好。而在C++中则可以使用new返回特定类型指针,更不容易出现问题,所以 void*的作用显得更弱了。

void*在C++中的主要作用就是作为函数指针的返回值[C++ Programming Language],例如:

void* my_alloc(size_t size);

void* 还用于一些底层的操作,例如我们有两个类UdpSocket和TcpSocket,在我们一个传输类中需要支持两种协议,提供统一的接口,但 UdpSocket和TcpSocket之间没有继承关系,无法使用共同的基类指针,而只能使用void*指针,代码如[??]。

class UdpSocket{};

class TcpSocket{};

class Transfer

{

public:

enum Protocol { UDP, TCP };

Transfer(Protocol prot) : _prot(prot)

{

if( _prot == UDP)

_sock = new UdpSocket( );

else if( _prot == TCP )

_sock = new TcpSocket( );

else

throw std::invalid_argument("prot");

}

~Transfer( void )

{

if(_prot == UDP)

delete (UdpSocket*)_sock;

else

delete (TcpSocket*)_sock;

_sock = NULL;

}

private:

void* _sock;

Protocol _prot;

};



本文转自莫水千流博客园博客,原文链接:http://www.cnblogs.com/zhoug2020/p/5416772.html,如需转载请自行联系原作者

相关文章
|
1月前
|
C++
C++ 数学函数、头文件及布尔类型详解
C++ 支持数学操作,如`max`和`min`函数找最大值和最小值,以及`&lt;cmath&gt;`库中的`sqrt`、`round`等数学函数。`bool`类型用于布尔逻辑,取值`true`(1)或`false`(0)。布尔表达式结合比较运算符常用于条件判断,例如在`if`语句中检查年龄是否达到投票年龄。在代码示例中,`isCodingFun`和`isFishTasty`变量分别输出1和0。
123 1
|
2月前
|
算法 编译器 C++
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits 判断 Lambda表达式类型?
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits 判断 Lambda表达式类型?
43 4
|
2月前
|
算法 编译器 C语言
【C++ 迭代器的空类类型 】深入理解C++迭代器类别与空类标签的奥秘
【C++ 迭代器的空类类型 】深入理解C++迭代器类别与空类标签的奥秘
35 0
|
2月前
|
存储 安全 C++
C++ 用户输入与数据类型详解:建立基本计算器及变量类型
了解C++的用户输入和数据类型。使用`cin`从键盘读取数据,如在简单计算器示例中获取两个数字并求和。C++的数据类型包括:`int`(整数)、`float`(浮点数,约6-7位小数)、`double`(更精确的浮点数,约15位小数)、`bool`(布尔值,true或false)、`char`(单个字符)和`string`(文本字符串)。每种类型都有特定的存储大小和用途。在处理浮点数时,`double`通常更安全。字符串需要包含`&lt;string&gt;`库。更多内容可关注微信公众号`Let us Coding`获取。
40 0
|
2月前
|
存储 安全 算法
【C/C++ 数据发送结构设计】C++中的高效数据发送:多态、类型擦除与更多解决方案
【C/C++ 数据发送结构设计】C++中的高效数据发送:多态、类型擦除与更多解决方案
79 0
|
2月前
|
存储 算法 编译器
【C++ 函数尾部返回】C++中的尾返回类型:探究auto func() -> ReturnType的魔力
【C++ 函数尾部返回】C++中的尾返回类型:探究auto func() -> ReturnType的魔力
64 1
|
2月前
|
算法 编译器 数据库
【C++ 泛型编程 高级篇】使用SFINAE和if constexpr灵活处理类型进行条件编译
【C++ 泛型编程 高级篇】使用SFINAE和if constexpr灵活处理类型进行条件编译
250 0
|
2月前
|
设计模式 程序员 C++
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
270 2
|
2月前
|
安全 程序员 编译器
【C/C++ 泛型编程 进阶篇 Type traits 】C++类型特征探究:编译时类型判断的艺术
【C/C++ 泛型编程 进阶篇 Type traits 】C++类型特征探究:编译时类型判断的艺术
185 1
|
2月前
|
算法 程序员 C++
【C/C++ 泛型编程 应用篇】C++ 对多参数的参数包的 参数类型提取 应用
【C/C++ 泛型编程 应用篇】C++ 对多参数的参数包的 参数类型提取 应用
44 5