C++ 的编程模块

2014/10/21 01:06 am posted in  C++

乐趣在于发现。


C++自带了一个包含函数的大型库,但真正的编程乐趣在于编写自己的函数。虽然语言越来越高级,C++也有强大的STL支持,但从创造到毁灭的乐趣才是无可替代的。

函数原型的功能

  1. 编译器正确处理函数的返回值
  2. 编译器检查使用的参数数目是否正确
  3. 编译器检查使用的参数类型是否正确

在C语言中,如果参数类型不正确则会导致错误,但是在C++中编译器会自动转化为正确的类型。(但是这样也会在函数重载中产生二义性),如果由大精度到小精度转换的时候编译器会发出警告,因此不要忽略任何一个警告。

有关数组方面,C++和C语言,将数组当指针处理。

至于数组和指针如何确定元素,《C++ PP》提出两个恒等式= =,

arr[i] == *(ar + i);

&arr[i] == ar + i;

tip:因为数组是指针传递,一定要注意数据保护,必要的时候可以使用const

对于程序设计,我们首先考虑的是通过数据类型和设计适当的函数处理数据,然后将这些函数组合成一个程序。有时也称为自下而上的程序设计,因为设计过程葱组件到整体进行。这种方法非常适合OPP,它首先强调的是数据表示和操纵。而传统的过程性编程倾向于从上而下的程序设计,首先制定模块化设计方案,然后再研究细节。这两种方法都很有用,优劣是相对而言的。最终的产品都是模块化程序。

对于把数组传参,一般有两种方法。

1.传递数组头地址和数组长度

2.传递数组头地址和尾地址。

第一种方法很常见,第二种方法挺有意思的。

对于double num[20];,我们可以传递num和num + 20,作为形参,指针num和num + 20定义了一个区间,是[num[0],num[19]],也就是说指向尾的指针是指向的最后一个元素的下一个元素(可能不存在)。

这样,对于数组遍历求和我们可以这样新颖的写:

for(pt = begin;pt != end;pt++)
total = total + *pt;

注意:根据指针减法规则,end-begin是一个整数值,等于数组的元素数目。

指针和const

指针和const的使用是一个很微妙的东西,可以有两种不同的方式将const关键之用于指针:

1.让指针指向一个常量对象,这样可以防止该指针修改所指向的值;

2.将指针本身声明为常量,可以防止改变指针指向的位置。

所有的操作,都是以这两个为基础的。

以前我们将常规变量的地址赋给常规指针,亦可以将常规变量的地址赋给指向const的指针(不可以用指针修改变量的值,但是可以用变量名修改)。因此还有两种可能性:

1.将const变量的地址赋给指向const的指针

2.将const的变量的地址赋给常规指针(非法)。

为什么第二种情况非法呢,因为常规指针是可以修改指向的值的,而指向的是一个const的值,那么编译器是不允许这么做的。

那么如果我们有一个const指针指向一个const常量,然后用一个指向指针指向这个const指针会如何呢?因为任何情况下编译器是允许将非const类型赋值给const指针的,因此描述二级间接关系,与一级间接关系一样将const和非const混合的指针赋值方式将不再安全。因此,仅当只有一层间接关系(如指针指向基本类型)时,才可以将非const地址或指针赋给const指针。

注意,如果数据类型本身并不是指针,则可以将const数据或非const数据的地址赋给指向const的指针,但只能将非const数据的地址赋给非const指针。

禁止将常量数据的地址赋给非常量指针将意味着不能讲数组名当做参数传递给使用非常量形参的函数。

因此,要尽可能的使用const

1.可以避免由于无意见修改数据而导致的编程错误

2.使用const使得函数可以处理const和非const实参,否则只能接受非const的数据。

如果条件允许,则应将指针形参声明为指向const的指针。

到底是指针是常量还是指针指向的常量呢?其实可以以为分界符,在左边有const就说明指向的内容不能改,在*右边就说明指针不能改,而左边的char和const顺序是不要紧的。

将指针作为函数形参来传递,可以使用指向const的指针保护。但是传递的必须是基本类型,比如

void show_array(const double ar[],int n);可以这样使用,但是如果这里的不是数组ar,而是指针甚至是指向指针的指针,不能保证只有一层的间接关系,则不能使用const。

对于函数和结构,要注意函数形参的特殊性,函数会把形参进行复制,如果结构过大,C语言一般采取传递地址的方法避免复制操作节省时间,而C++还支持引用。

函数和指针

指针和函数联用是个很高大上的东西,和数据一样,函数也是有地址的,这些地址对用户没有啥用,但是对于程序用处很大,可以编写将另一个函数地址作为参数的函数,这样第一个函数就能够找到第二个函数。使用起来将十分的灵活。

获取函数地址的方式和数组一样,函数名就是函数的地址。

对于声明函数指针,因为括号的运算级要高于*号,所以声明函数指针时要加括号,比如:double (*pf) (int);

其中pf便是指向形参为int,返回值为double的函数。

使用函数指针调用函数:

double pam(int);
double (*pf)(int);
pf = pam;
double x = pam(4);
double y = (*pf)(5);

//C++还允许这样使用
double y = pf(5);

虽然第一种方式不好看,但他明确的提示——正在使用函数指针。

函数指针的表示可以非常的恐怖,实现的功能也可以十分恐怖,比如用一个函数指针数组存储几个函数,用for循环依次执行这几个函数

但对于太恶心的指针可以使用auto,auto只允许但只初始化,不允许列表初始化。

自动类型推断确保变量的类型与赋给它的初值的类型一致,但一定要保证提供的初值的类型正确。


第七章终于写完了,要在一堆已经会的东西找出不太牢固的着实是个耐心活><,写到现在也是醉了。