C++基础学习之编程模块(4)

函数和二维数组

在C++中,二维数组的定义完全与一维数组不同:

int data[3][4] = {{1, 2, 3, 4}, {9, 8, 7, 6}, {2, 4, 6, 8}};

data不能当作是一维数组的指针然后去访问12个元素,data[0~2]每个都是一个一维数组的指针,也就是说其实data是指针的指针。
所以在子函数中用的时候需要如下声明:

int sun(int arr[][4], int size);

注意这里把每个子指针指向的列数写出来了,所以传入的参数也只能是列数为4的二维数组。如果不写的话,直接写成arr[][],那么应该是可以传入任意二维数组的。

内联函数

内联函数其实就是相当于在把调用函数的过程替换成了直接执行代码段,也就是说一般的函数都是需要跳出去调用完再回到主函数,而内联函数直接就在编译时把调用代码换成了函数代码段,所以节省时间的同时其实带来了空间的负担。这种函数的好处是当子函数内容不多,调用代价比直接执行用的时间长很多时,就有必要节省调用时间了,所以需要内联函数。
内联函数用法:

  • 在函数声明前加上关键字inline
  • 或者在函数定义前加上关键字inline
    通常的做法是省略原型,将整个定义(即函数头和所有函数代码)放在本应提供原型的地方。要注意的是内联函数不能递归。
    这个功能与C语言的宏定义有些类似,但是比C语言宏定义要好写很多,好用很多。

引用变量

引用是已定义变量的别名。也就是说就是同一个变量有两个名字。(python语言的特性里有)。引用变量的主要用途是用作函数的形参,这样函数将使用原始数据,而不是副本。这样除指针以外,引用也为函数处理大型结构提供了一种非常方便的途径,同时对于设计类来说,引用也是必不可少的。

创建引用变量

C和C++都使用&符号来指示变量的地址。C++给&符号赋予了另一个含义,将其用来声明引用。例如,要将rodents作为rats变量的别名,可以这样做:

int rats;
int & rodents = rats;	// makes rodents an alias for rats

其中,&不是地址运算符,而是类型标识符的一部分。就像声明中的char*指的是指向char的指针一样,int&指的是指向int的引用。上述引用声明允许将rats和rodents互换——它们指向相同的值和内存单元。
必须在声明引用时将其初始化,不能像指针那样先声明再赋值。而且引用更接近const指针,必须在创建时进行初始化,一旦与某个变量关联起来,就将一直效忠于它。也就是说,不能改。
按引用传递示例:

void grumpy(int &x);
int main()
{
	int times = 20;
	grumpy(times);
	...
}
void grumpy(int &x)	// 这里使x成为times的别名,与times同一个变量,地址相同。
{
	...
}

按引用传递和安值传递看起来调用函数时是相同的。只能通过原型或函数定义才能知道是按引用传递的。之前说过,应在定义引用变量时对其进行初始化。函数调用使用实参初始化形参,因此函数的引用参数被初始化为函数调用传递的实参。所以指向的都是同一个值。

引用的属性和特别之处

使用引用传参时可能会改变原始的值,所以当想要使用引用传参但不想改变原始值时,可以使用const,例如上例中可以这样写:void grumpy(const int &x),这样如果子函数中对x进行更改编译器就会报错。其实当传递单个值时最好还是使用值传递,无需使用引用, 只有当想传递类,结构等较大的数据结构时,为了节省空间或者时间,可以使用引用传参。
引用传参传递的参数必须是一个变量,不能是算式,也就是说必须在内存中有地址而且有名字。否则C++会产生临时变量,编译器会发出警告。
应该尽可能的使用const:

  • 使用const可以避免无意中修改数据的编程错误;
  • 使用const使函数能够处理const和非const实参,否则将只能接受非const数据;
  • 使用const引用使函数能够正确生成并使用临时变量。

将引用用于结构

使用结构引用参数的方式与使用基本变量引用相同,只需在声明结构参数时使用引用运算符&即可。示例如下:

struct free_throws
{
	std::string name;
	int made;
	int attempts;
	float percent;
};
void set_pc(free_throws & ft);
// 或者
void display(const free_throws & tf);

引用也可以作为返回值,表示返回的是原始的值,否则返回一个拷贝值。

free_throws & accumulate(free_thorws & target, const free_throws & source);

返回引用时需要注意的是应避免返回函数终止时不再存在的内存单元引用。

将引用用于类对象

将类对象传递给函数时,C++通常的做法是使用引用。例如string就是一种类,可以像基本类型引用那样使用类的引用。

函数模板

函数模板是通用的函数描述,也就是说,它们使用泛型来定义函数,其中泛型可用具体的类型(如int或double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。下面是一个建立交换模板的例子:

template <typename AnyType>
//或者更常用的一种形式
template<class T>
void Swap(T &a, T &b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}

之后只要调用Swap函数,无论是什么类型都可以迅速创建函数然后使用。一般来说都会把模板放在头文件中,并在需要使用模板的文件中包含头文件。模板也可以被重载,只要写两个然后参数列表不同即可。
这种模板函数显然对于数组或者结构体无法操作,因此还有一种建立模板的方式叫做显示具体化模板:

struct job
{
	char name[40];
	double salary;
	int floor;
};
template <> void Swap<job>(job &, job &);	// 原型

// 实现函数
template <> void Swap<job>(job &, job &)
{
	...
}

可以看出其实显示具体化就是针对特定的数据结构写一个特定数据结构的模板。
还有一种声明是显示实例化,就是声明一个特定数据类型的函数供使用:

tmplate <> void Swap<int>(int &, int &);

直接指定类型,然后就可以在下面直接使用了,如果不用这句话就是隐式声明,用了这句话就是显示声明,感觉没啥用…(可能是显示声明之后更清楚吧…)
总之模板函数很强,所以C++专门建立了标准模板库供人们使用,而使用方法就是类似上面的声明就好(包含头文件之后)。

猜你喜欢

转载自blog.csdn.net/x603560617/article/details/83274437