第十九章:特殊工具与技术

本文介绍了C++中的特殊工具和技术,如内存控制(自定义new和delete),运行时内存识别(typeid和dynamic_cast),枚举类型,类成员指针,嵌套类,联合(union),局部类,位域和volatile特性,以及C++的链接指示和跨语言编译。
摘要由CSDN通过智能技术生成

第十九章:特殊工具与技术

对于很多程序员来说,他们很少会用到本章的介绍的内容。

一.控制内存分配

我们能够重载new和delete,但其实不是对new和delete的重载,只是对new和delete操作符后面的函数进行重载。

当我们使用一条new表达式的时候,第一步new表达式调用一个名为operator new或operator new [] 的函数分配内存空间。第二步,编译器运行构造函数构造对象并传入初始值,第三步,返回一个指向该对象的指针。

当我们使用一条delete表达式的时候,第一步执行析构函数,第二步调用operator delete或operator delete []释放内存空间。

如果希望控制内存分配的过程,可以定义自己的operator new函数和operator delete函数。可以在全局作用域中定义这两个函数,也可以定义为成员函数。当编译器发现一条new或delete表达式时且对象是类类型,则先在类和基类的作用域中找这两个函数。当我们定义为成员函数时,这两类函数是隐式静态的。因为operator new用在对象构造之前,operator delete用在对象析构之后,所以必须是静态的且不能使用类的任何数据成员。

要实现这两类函数,可以使用malloc和free。

二.运行时内存识别

运行时内存识别的功能由两个运算符实现:typeid:用于返回表达式的类型;dynamic_cast:用于将基类的指针或引用安全的转换成派生类的指针或引用。

RTTI可以让我们在不能使用虚函数的情况下实现多态。

typeid操作的结果是一个常量对象的引用,该对象的类型是标准库类型type_info或type_info的公有派生类型。

当typeid作用于指针时(而非指针所指的对象),返回的结果是该指针的静态编译类型。

如果表达式的动态类型和静态类型不同,typeid会在运行时对表达式求值以确定返回的类型。

三.枚举类型

枚举类型使我们可以将一组整形常量组织在一起。每个枚举类型定义了一种新的类型,枚举属于字面值常量类型。

C++包含两种枚举:限定作用域和不限定作用域的。限定作用域是C++11新标准引入的,定义方式为在定义的时候在enum后面加上class或struct。

在限定作用域的枚举类型中,枚举成员的名字遵循常规的作用域准则,并且在枚举类型的作用域外是不可访问的(可以用作用域运算符访问);在不限定作用域的枚举类型中,枚举成员的作用域与枚举类型本身的作用域相同。

默认情况下,枚举值从0开始,依次加1,不过我们也能为一个或几个枚举成员指定专门的值。枚举值不一定唯一。枚举成员是const的。

enum是由某种整型类型表示的,在C++11新标准中,我们可以在enum的名字后加上冒号以及我们想在该enum中使用的类型。如果不加,限定的默认是int,非限定的默认不知。

四.类成员指针

成员指针是指可以指向类的非静态成员的指针。一般情况下指针指向一个对象,但是成员指针指向的是类的成员,而不是某个特定对象。

成员指针的类型囊括了类的类型及成员的类型。当初始化一个这样的指针时,我们令其指向类的某个成员,但是不指定该成员所属的对象;直到使用成员指针时,才提供成员所属的对象。

常规的访问控制规则对成员指针同样有效。

五.嵌套类

一个类可以定义在另一个类的内部,前者称为嵌套类或嵌套类型。

嵌套类和外部类没有什么特别的关系,只是嵌套类位于外部类的作用域中,受外部类的访问控制,两者都不含对方的成员。

六.union:一种节省空间的类

联合(union)是一种特殊的类。可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。分配给一个union对象的存储空间至少要能容纳它的最大成员。union可以为其成员指定public,protected和private等标记,默认为public。可以定义包括构造函数和析构函数在内的成员函数,不能定义虚函数。

匿名union是一个未命名的union,并且在右花括号和分号之间没有任何生命。一旦我们定义了一个匿名union,编译器就会自动为该union生成一个未命名的对象,在匿名union所在的作用域内该union的成员都是可以直接访问的。

对于union来说,要想构造或销毁类类型的成员必须执行非常复杂的操作,因此我们通常把含有类类型成员的union内嵌在另一个类中。这个类可以管理并控制与union的类类型成员有关的状态转换。

七.局部类

类可以定义在函数的内部,我们称这样的类为局部类。局部类定义的类型只在定义它的作用域可见。局部类的所有成员(函数在内)都必须完成定义在类的内部。局部类不允许声明静态成员。

局部类只能访问外层作用域定义的类型名、静态变量以及枚举成员。

八.固有的不可移植的特性

为了支持低层编程,C++定义了一些固有的不可移植的特性。所谓不可移植是指因机器而异。

类可以将其非静态成员定义为位域,在一个位域中含有一定数量的二进制位。当一个程序需要向其他程序或硬件设备传递而二进制数据时,通常会用到位域。

位域在内存中的布局是与机器相关的。

位域的类型必须是整型或枚举类型。通常是无符号类型。位域的声明形式是在成员名字之后紧跟一个冒号以及一个常量表达式,该表达式用于指定成员所占的二进制位数。

取地址运算符不能作用于位域,因此任何指针都无法指向类的位域。

当对象的值可能在程序的控制或检测之外被改变时,应该将该对象声明为volatile。关键字volatile告诉编译器不应对这样的对象进行优化。

volatile的确切含义与机器有关,只能通过阅读编译器文档来理解。

就像一个类可以定义const成员函数一样,它也能将成员函数定义为volatile的。只能volatile的成员函数才能被volatile的对象调用。

和const一样,我们只能将一个volatile对象的地址赋给一个指向volatile的指针。对引用也一样。

我们不能使用合成的拷贝/移动函数及赋值运算符初始化volatile。

C++使用链接指示指出任意非C++函数所用的语言。

对于使用链接指示定义的函数来说,它的每个声明都必须使用相同的链接指示,指向其他语言编写的函数的指针必须与函数本身使用相同的链接指示。

指向C函数的指针和指向C++函数的指针是不一样的类型,不能混用。

当我们使用链接指示时,它不仅对函数有效,而且对作为返回类型或形参类型的函数指针也有效(即若它的形参或返回类型是函数指针的话,则也是那种语言的函数指针)。所以如果我们希望给C++函数传入一个指向C函数的指针,则必须使用类型别名。

有时需要在C和C++中编译同一个源文件,为了实现这一目的,在编译C++版本的程序时预处理器定义__cplusplus。利用这个变量,我们可以在编译C++程序的时候有条件地包含进来一些代码。

完结撒花!!!🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值