函数指针是指针,指向一个函数的入口地址;指针函数是函数,返回值是指针。
int* funTest(int a[])
{
return a;
}
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
int* p = funTest(arr);
for (int i = 0; i < 5; i++)
{
cout << p[i] << endl;
}
}
定义了一个返回值为int*
,输入参数为a[]
的指针函数,调用该函数返回数组a的首地址。
int add(int x, int y)//加
{
return x + y;
}
int sub(int x, int y)//减
{
return x - y;
}
typedef int (*pFun)(int, int);
int main()
{
int (*fun)(int, int);
fun = add;//指向add函数,注意:fun = add 和 fun = &add一致,都是指向了函数的入口地址
cout << fun(2, 1) << endl;
fun = sub;
cout << fun(2, 1) << endl;
pFun fp;
fp = add;
cout << fp(2, 3) << endl;
return 0;
}
函数指针,本质上是指针,只不过用来指向函数的地址,可以替代函数,并可切换指向,指向不同的函数。
注意,定义函数指针时,因为*
的优先级较小,所以需加括号,如:void (*pfun)()
就定义了一个返回值为空、参数列表为空的函数指针,可以指向相同格式的函数。
函数指针可以有两种定义方式,两者用法一致:
//1.
int (*fun)(int, int);
//2.
typedef int (*pFun)(int, int);
pFun fun;
从英文翻译中文意思就是:易变的、不稳定的。所以,一个变量在加了volatile修饰后,要求编译器禁止对volatile变量进行优化,在每个变量赋值时需显式地从寄存器拷贝。在嵌入式编程中比较多用到,因为可能发生中断修改了寄存器的值或一段汇编代码修改了值而不让编译器知道,这时候就要加上volatile。
注意,在C++中volatile与并发编程有关是个错误!原因可能是java中的volatile和C++是不一样的。
参考这篇博客:C++volatile的误会
int *p[10]
int (*p)[10]
int *p(int)
int (*p)(int)
int *p[10]
是指针数组,强调数组概念,是一个数组变量,数组大小为10,数组内每个元素都是指向int类型的指针变量。int (*p)[10]
表示数组指针,强调是指针,只有一个变量,是指针类型,不过指向的是一个int类型的数组,这个数组大小是10。int *p(int)
是函数声明,函数名是p,参数是int类型的,返回值是int *类型的。int (*p)(int)
是函数指针,强调是指针,该指针指向的函数具有int类型参数,并且返回值是int类型的。*__vptr
。虚函数指针自动地指向虚表中对应的位置,找到相应的成员函数。new / malloc都是动态内存的开辟,在堆区开启空间;而delete / free都是动态内存的释放。
#include
void*
,这时候我们用一种类型指针接收,但是malloc开辟的空间可能大于设定的类型,理论上会出错但是使用malloc编译器不会出错,而使用new编译器会报错。像C/C++、java、C#等语言都是强类型语言:
而JavaScript、Python、PHP、Ruby等语言是弱类型语言,在定义变量时不用显示地指明数据类型,解释器会根据赋给变量的数据自动推导出数据类型。
如下,是JavaScript 中使用变量,var 是 JavaScript 中的一个关键字,表示定义一个新的变量,而不是数据类型。
var a = 10;
a = 13.5;
对比:
C++模板模板的提出,正是为了弥补强类型语言"不够灵活"的缺点。模板所支持的类型是宽泛的,没有限制的,我们可以使用任意类型来替换,这种编程方式称为泛型编程(Generic Programming)
C++的STL标准模板库,几乎整个库都是通过模板来完成的。比如各种数据结构:线性表、链表、树、图都定义好一个模板类,程序员只要调用库就可,不用重复造轮子。
模板:模板是C++中泛型编程的基础。一个模板就是一个创建类或函数的蓝图或者说公司。
模板在编译阶段就能知道其类型了:
template <typename T>
int compare(const T &v1, const T &v2)
{
if (v1 < v2) return -1;
else if (v1 > v2) return 1;
else return 0;
}
当我们调用一个函数模板时,cout << compare(1, 2) << endl
,编译器通过函数实参推断模板实参,并绑定到模板参数T。如上例子,编译器推断出类型为int
,并绑定到模板参数T。
编译器用推断出的模板参数为我们实例化一个特定版本的函数,如上例,T的类型就是int。编译器实例化一个模板时,它使用实际的模板实参代替对应的模板参数来创建出模板的一个新的"实例":
int compare(const int &v1, const int &v2)
{
if (v1 < v2) return -1;
else if (v1 > v2) return 1;
else return 0;
}
所以说,泛型编程在编译阶段就已经确定了数据的类型,注意区别:多态是运行时确定的。