C++变量声明再探讨

前言

每每学到指针,总会有这些知识点来折磨我们:

“int* a[3]”和“int (*a)[3]”不一样哟!一个是指针数组一个是数组指针;

“const int* a”和“int * const a”不一样哟!一个是可改a不可改*a,一个是可改*a不可改a;

“int* p()”和“int(*p)()”不一样哟!一个是函数一个是指针。

……

如果老师只念ppt,也许这些知识只能硬背。

1 基本声明格式

这一节主要是复习,声明原则在第二节

1.1普通变量

众所周知,C++中声明变量的方式是:

T var;

T是变量类型,var是变量名。比如声明一个int:

int a;

声明一个double:

double b;

这都很简单,相信你也是会的。这里就不赘述了。
请记住这个基本原则。

1.1 C语言部分:数组、函数、指针

如何声明一个数组?

T array[N];

T是类型,N是一个编译期间可确定的常量。可以说,声明一个元素是T类型的数组的语法,就是在变量名后面加个"[N]"

那么,函数呢?

T func(ArgType1, ArgType2, ...);

比如一个参数类型是int的、返回值是double的函数,声明时只需要这样即可:

double func(int);

参数名在声明时可以不写,这是我们知道的语法。
所以可以总结为,声明一个返回值类型是T的函数,就是在变量名后面加个(ArgType1, ArgType2…)的参数类型列表

指针呢?指针就是在变量名前面加个*。比如指向int的指针,声明为:

int *p;

1.2 C++部分:引用

这里不介绍什么是引用,单说一下声明。声明一个引用T类型变量的左值引用的语法,类似指针,就是在变量名前面加个&

int &ref;

当然,左值引用必须在声明时初始化。如果声明右值引用,那就是加&&。

2 变量声明原则

2.1 核心:变量声明原则

经过第一节的复习,聪明的你一定发现了:只要我们在变量名上动一下手脚,就可以声明指针/函数/引用/数组。这里总结一下这个原则:

以变量名为中心,先右后左地结合,按下面的方式翻译变量类型:

  • 左边加*是指针,a pointer to
  • 左边加&是引用(加&&是右值引用),the reference of
  • 右边加(…)是函数,a function with argument (…) that returns
  • 右边加[N]是数组,an N-sized array of

2.2 核心:声明原则的举例理解

这个原则怎么应用呢?看一下下面的例子:

int *a[3];
int (*b)[3];
int (*c)(int, char);
int (*d(double))(int)

a,先右后左,所以先和[3]结合,我们写下:
a is a 3-sized array of
然后把[3]去掉,剩int *a。

对int *a,我们先右后左,那就是与 * 结合,我们接着上面的那句话往下添加pointer to:
a is a 3-sized array of pointer to
然后去掉*,剩下int a。

对int a,先右后左,与int结合,直接落下来:
a is a 3-sized array of pointer to int
翻译成汉语:a是一个长度为3、装有指向int的指针的数组。即,int *a[3]是数组。

那么就按照这个模式结合,我们可以得到abcd的类型分别是:

  • a is a 3-sized array of pointer to int.
    a是装了3个int*的数组
  • b is a pointer to a 3-sized array of int.
    b是指向int[3]的指针
  • c is a pointer to a function with argument (int, char) that returns int。
    c是指向一个函数的指针,函数类型:int(int, char)【返回值int,参数类型为int, char】
  • d is a function with argument (double) that returns a pointer to a function with argument (int) that returns int.
    d是参数类型为double,返回一个函数指针的函数,这个函数指针指向一个int(int)【返回值int,参数类型(int)】的函数。

你学会了吗?

2.3 初始化语句

初始化的值永远都要写在声明的后面

比如初始化一个函数指针和一个数组引用:

int array[10];
int(*p)(int,int) = nullptr; //pointer to function int(int,int)
int (&r)[10] = array; //reference of a 10-sized array of int

=nullptr、=array这些初始化值,要写在声明语句结束之后,而不是写在p、r的后面。

2.4 扩展:成员函数指针

普通函数指针和成员函数指针对比一下,如下:

class T{};
int (*pFunc)(int) = nullptr;
int (T::*pMethod)(int) = nullptr;

是的,成员函数指针要加一个T::,而且括号要括在(T::*p)这个外面,而不是T :: (*p)。
普通函数指针和成员函数指针的用法对比一下:

(*pFunc)(10); //ok
pFunc(10); //ok
T obj;
(obj.*pMethod)(10); //ok
//obj.pMethod(10); //不ok, 会报错

是的,普通函数指针有不用加*的语法糖,成员函数没有,必须得老老实实的(obj.*pMethod)(10)

3 typedef与using

经过第二节的介绍,你会发现:类型但凡复杂一点,声明语句就可读性极差。比如一个返回数组指针的函数,应该这么写:

int (*func(int *p))[10]{
	return (int(*)[10])p;
}

这**是人能读的东西啊?
C语言为此出了个typedef,到了C++里又可以用using

3.1 typedef

用法:typedef 变量声明语句
作用:声明语句声明出来的那个名字不再是变量名,而是这个类型的别名

例子:

typedef int IntArray[3];
IntArray3 arr = {1,2,3};

正常来讲,int IntArray[3]声明出来的IntArray应该是一个长度为3的int数组,但是加了typedef之后,IntArray就不再是一个类型是int[3]的变量了,而是int[3]的别名。你可以直接把它当类型用。

这样就可以把函数指针简写了:

typedef void (*p_event)(int);
p_event makeEvent(){
	return nullptr;
}
//如果不用p_event的话,makeEvent的定义应该这么写:
void (*makeEvent_another())(int){
	return nullptr;
}

3.2 using的类型起名用法

typedef是用变量声明语句来声明类型别名,using则是后面直接接一个类型。也就是下面的p_func和上面的p_event一样,都是void(*)(int):

using p_func = void(*)(int);

结语

祝大家学习cpp顺利!

  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值