C++复合类型
复合类型是指基于其他类型定义的类型。C++有几种复合类型,下面主要是引用
和指针
。
定义复合类型的变量复杂很多,通用的描述为:一条声明语句由一个基本数据类型
和紧随其后的一个声明符
列表组成。每个声明符命名了一个变量并指定该变量为与基本数据类型有关的某种类型。
——————————-
引用
C++11中新增加了一种引用,为右值引用
,主要用于内置类。这里,我们使用引用
时,指的是左值引用
。
引用为对象起了另外一个名字,引用类型引用另外一种类型。通过将声明符写成&d
的形式来定义引用类型,其中d是声明的变量名。
引用即别名,并非对象,它只是为一个已经存在的对象所起的另外一个名字。
下面是引用的一个例子。
#include <iostream>
using namespace std;
int main()
{
int vale = 1024;
int &vale00 = vale; //注意:引用必须进行初始化
cout << "vale的值为:" << vale << endl;
cout << "vale00的值为:" << vale00 << endl;
cout << "vale00是vale的引用。" << endl;
}
定义了一个引用之后,对其进行的所有操作都是在与之绑定的对象上进行的。
为引用赋值,实际上是把值赋给了与引用绑定的对象。获取引用的值,实际上是获取到了与之绑定的对象的值。同理,以引用作为初始值,实际上是以引用绑定的对象作为初始值。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name = "青木";
string &name_ = name;
string name0 = "Aoki";
cout << "大家好,我的名字是" << name_ << endl;
cout << "大家好,我是" << name0 << endl;
name0 = name_;//为引用赋值
cout << "大家好,我现在是" << name0 << endl;
}
输出结果为:
指针
指针
是指向另外一种类型的复合类型。与引用类似,指针也实现了对其他对象的间接访问,但是指针与引用也有很多不同点,如下:
- 指针本身就是个对象,允许对指针赋值和拷贝,在指针的生命周期内,它可以先后指向几个不同的对象
- 指针无须在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有定义,也将拥有一个不确定的值。
获取对象的地址
指针存放某个对象的地址,要向获取该地址,就要使用取地址符
(&)。
在声明语句中,指针的类型实际上被用于它所指向的对象的类型,所以二者必须匹配。如果指针指向了一个其他类型的对象,对该对象的操作将会发生错误。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name = "青木";
string* name_=&name;//name_存放变量name的地址,或者说name_是指向变量name的指针
cout << "大家好,我的名字是" << name << endl;
cout << "name的地址为:" << name_ << endl;
cout << "大家好,我的名字是" << name_ << endl;
}
输出结果为:
指针值
指针的值(即地址)应属于下列4中状态之一:
- 指向一个对象
- 指向紧邻对象所占空间的下一个位置
- 空指针,意味着指针没有指向任何值
- 无效指针,就是上述状态之外的其他值。
对于无效指针,试图拷贝或以其他方式访问无效指针的值都将引发错误。
利用指针访问对象
如果一个指针指向了一个对象,则允许使用解引用符
(*)来访问该对象。
对指针解引用会得到所指的对象,因此如果给解引用的结果赋值,实际上也就是给指针所指的内容赋值。
注意:解引用操作仅适用于那些确实指向了某个对象的有效指针。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name = "青木";
string name0 = "Aoki";
string* name_=&name;//name_存放变量name的地址,或者说name_是指向变量name的指针
cout << "大家好,我的名字是" << name << endl;
cout << "name的地址为:" << name_ << endl;
cout << "大家好,我的名字是" << *name_ << endl;//指针解引用,获取对象的值
*name_ = name0;//经由指针为name赋值
cout << "大家好,我的名字是" << name << endl;
cout << "大家好,我的名字是" << *name_ << endl;
}
空指针
空指针不指向任何对象,在试图使用一个指针之前,代码可以首先检查它是否为空。
生成空指针的方法:
int* p1=nullptr;//等价于int* ptr=0
int* p2=0;//直接将p2初始化为字面常量0
得到空指针最直接的办法是使用字面值nullptr来初始化指针。nullptr是一种特殊的指针,它可以被转换成任意其他指针类型。
赋值和指针
指针额引用都能够提供对其他的对象的间接访问,但是在具体的实现细节上两者有很大不同,其中最主要的又掉了是引用本身并不是一个对象。
指针和它存放的地址之间没有这种限制。和其他任何变量一样,给指针赋值就是令它存放一个新地址,从而指向一个新对象。
对于指针的赋值,前文已经给出。
其他指针操作
只要指针拥有一个合法值,就能将它用在条件表达式中。和采用算术值作为条件遵循的规则一样,如果指针的值是0,条件取false。
对于两个类型相同的合法指针,可以用相等操作符或不相等操作符来比较它们,比较的结果是布尔类型。
两个指针存放的地址值相同(两个指针相等),有三种可能:
- 它们都为空
- 都指向同一个对象
- 都指向同一个对象的下一个地址
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name = "青木";
string* name_=&name;//name_存放变量name的地址,或者说name_是指向变量name的指针
int* a = nullptr;
if (name_&&a) //与运算,一真一假为假
cout << "大家好,我是指向" << name << "的指针,我不为空" << endl;
else
cout << "大家好,我是空指针a,我的地址是" << &a << endl;
}
输出结果如下:
最后是void*指针。
void* 指针
void* 指针是一种特殊的指针类型,可用于存放任意对象的指针,一个void指针存放着一个地址。
利用void指针可以做的事有:
- 拿它和别的指针比较
- 作为函数的输入和输出
- 赋值给另外一个void*指针
但是我们不能直接操作void* 指针,因为它的类型未知。以void*的视角来看内存空间也仅仅是内存空间,没办法访问内存空间中所存的对象。
#include <iostream>
#include <string>
using namespace std;
int main()
{
int a = 10;
int* name_=&a;//name_存放变量a的地址,或者说name_是指向变量a的指针
void* names;
names = name_;
cout << "name_指向的值为:" << *name_ <<",地址为:"<<name_<< endl;
cout << "names地址为:" << names << endl;
}
输出结果:
对于void* 指针,我还有许多不解的地方,在网上搜索之后发现了一个比较详细解释void* 指针的博文——void及void指针含义的深刻解析