C++ primer 注意的知识点(第7章)

1)      函数形参表可以为空,但不能省略。没有任何形参的函数可以用空形参表或含有单个关键字 void 的形参表来表示。例如,下面关于 process 的声明是等价的:

void process() { /* ... */ }      // implicit void parameter list

void process(void){ /* ... */ }  // equivalent declaration

(注意:C++是这样,C语言两者有区别)

2)      更灵活的指向 const 的引用,关于为什么作者极力推荐const的引用总结如下:

a)      如果函数具有普通的非 const 引用形参,则显然不能通过 const 对象进行调用。毕竟,此时函数可以修改传递进来的对象,这样就违背了实参的 const 特性。写一个例子在这:

void fun(string& s)

{

}

int main()

{

   const string str = "China";

   fun(str);//在此不能调用成功,如果加上const的话,则可以通过

   return 0;  

}

b)      调用这样的函数时,传递一个右值或具有需要转换的类型的对象同样是不允许的。附一段书上的例子:

int incr(int &val)

{

   return ++val;  

}

int main()

{

   short v1 = 0;

   const int v2 = 42;

   int v3 = incr(v1);   // v1类型为short,不匹配

   v3 = incr(v2);       // v2const,显然不行

   v3 = incr(0);        //字面值是常量,不存在有一个非const引用

   v3 = incr(v1 + v2);  // 这应该就是所谓的传递一个右值

   int v4 = incr(v3);   // 这个可以通过

}

当把函数形参改为const引用的话,则除了return ++val这条语句不能通过,其它的都能通过。如果你没看懂这是为什么的话,那么在此写上一句提示,前面的文章也当过重点的:const 引用可以初始化为不同类型的对象或者初始化为右值。

c)      const 引用形参只能与完全同类型的非 const 对象关联。应该将不修改相应实参的形参定义为 const 引用。如果将这样的形参定义                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         为非 const 引用,则毫无必要地限制了该函数的使用。

3)      通常,函数不应该有 vector 或其他标准库容器类型的形参。调用含有普通的非引用 vector 形参的函数将会复制 vector 的每一个元素。从避免复制 vector 的角度出发,应考虑将形参声明为引用类型。然而,看过第十一章后我们会知道,事实上,C++ 程序员倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器。

4)      一般情况下,返回类型是 void 的函数使用 return 语句是为了引起函数的强制结束,这种 return 的用法类似于循环结构中的 break 语句的作用。返回类型为 void 的函数通常不能使用return expression语句,但是,它可以返回另一个返回类型同样是 void 的函数的调用结果:

void do_swap(int &v1, int &v2)

{

     int tmp = v2;

     v2 = v1;

     v1 = tmp;

     // ok: void function doesn't need an explicit return

}

void swap(int &v1, int &v2)

{

    if (v1 == v2)

         return false; // error: void function cannot return a value

return do_swap(v1, v2); // ok: returns call to a void function

} 

5)      返回类型不是 void 的函数必须返回一个值,但此规则有一个例外情况:允许主函数 main 没有返回值就可结束。如果程序控制执行到主函数 main 的最后一个语句都还没有返回,那么编译器会隐式地插入返回 0 的语句。关于主函数 main 返回的另一个特别之处在于如何处理它的返回值。在第 1.1 已知,可将主函数 main 返回的值视为状态指示器。返回 0 表示程序运行成功,其他大部分返回值则表示失败。非 0 返回值的意义因机器不同而不同,为了使返回值独立于机器,cstdlib 头文件定义了两个预处理变量(第 2.9.2 ),分别用于表示程序运行成功和失败。

   #include <cstdlib>

   int main()

   {

       if (some_failure)

           return EXIT_FAILURE;

       else

           return EXIT_SUCCESS;

   }

6)      返回引用的函数返回一个左值。因此,这样的函数可用于任何要求使用左值的地方,如果不希望引用返回值被修改,返回值应该声明为 const

char &get_val(string &str, string::size_type ix)

//const char &get_val(...)

 

   {

       return str[ix];

   }

   int main()

   {

       string s("a value");

       cout << s << endl;   // prints a value

       get_val(s, 0) = 'A'; // changes s[0] to A

 

       cout << s << endl;   // prints A value

       return 0;

   }

7)      如果有一个形参具有默认实参,那么,它后面所有的形参都必须有默认实参。(原因知道一点,但说实话不是很透彻)。举个百度知道上的一个网友gym1039举的例子:

void m(int a,char v,float f=0.0);

void m(int a=0,int v,int f);

假如你要调用第二个方法,请问你怎么调用呢?

如果你想这样m(2,3),那2编译器只能认为是int a的,3只能认为是int v的,而且这样也不对啊,那int f呢?所以只有像第一种方法那样,可选参数放在后面,从右往左排列编译器才会识别!

8)      内联函数应该在头文件中定义,这一点不同于其他函数。

9)      const改变了隐含的this形参的类型。在调用 total.same_isbn(trans) 时,隐含的 this 形参将是一个指向 total 对象的 const Sales_Item* 类型的指针。用这种方式使用 const 的函数称为常量成员函数。由于 this 是指向 const 对象的指针,const 成员函数不能修改调用该函数的对象。因此,函数 avg_price 和函数 same_isbn 只能读取而不能修改调用它们的对象的数据成员。const 对象、指向 const 对象的指针或引用只能用于调用其 const 成员函数,如果尝试用它们来调用非 const 成员函数,则是错误的。

10)  形参与 const 形参的等价性仅适用于非引用形参。有 const 引用形参的函数与有非 const 引用形参的函数是不同的。类似地,如果函数带有指向 const 类型的指针形参,则与带有指向相同类型的非 const 对象的指针形参的函数不相同。

11)  可基于函数的引用形参是指向 const 对象还是指向非 const 对象,实现函数重载。将引用形参定义为 const 来重载函数是合法的,因为编译器可以根据实参是否为 const 确定调用哪一个函数:

Record lookup(Account&);

  Record lookup(const Account&); // new function

    const Account a(0);

    Account b;

    lookup(a);   // calls lookup(const Account&)

    lookup(b);   // calls lookup(Account&)

如果传递的是非 const 对象,则上述任意一种函数皆可行。非 const 对象既可用于初始化 const 引用,也可用于初始化非 const 引用。但是,将 const 引用初始化为非 const 对象,需通过转换来实现,而非 const 形参的初始化则是精确匹配。

但是对于形参不是引用或者指针的话,则认为是重复

void fcn(const int i) { /* fcn can read but not write to i */ }

  void fcn(int i) { /* ... */ }            // error: redefines fcn(int)

原因前面已经说过了,这里就不重复了。

另外这里扩展一下如果对于类的成员函数的话,常量成员函数和普通成员函数也是会发生函数重载,因为这个是一个constthis指针啊,所以还是前面的知识。

在这里还有一个比较容易迷惑的一个例子,就是注意不能基于指针本身是否为 const 来实现函数的重载:

     f(int *);

     f(int *const); // redeclaration

在上述两种情况中,都复制了指针,指针本身是否为 const 并没有带来区别。正如前面所提到的,当形参以副本传递时,不能基于形参是否为 const 来实现重载。

12)  函数可以返回指向函数的指针,但是,正确写出这种返回类型相当不容易:

int (*ff(int))(int*, int);

   阅读函数指针声明的最佳方法是从声明的名字开始由里而外理解。要理解该声明的含义,首先观察: ff(int) ff 声明为一个函数,它带有一个 int 型的形参。该函数返回int (*)(int*, int); 它是一个指向函数的指针,所指向的函数返回 int 型并带有两个分别是 int* 型和 int 型的形参。

  使用 typedef 可使该定义更简明易懂:

typedef int (*PF)(int*, int);

PF ff(int);  // ff returns a pointer to function

允许将形参定义为函数类型,但函数的返回类型则必须是指向函数的指针,而不能是函数。

// func is a function type, not a pointer to function!

 typedef int func(int*, int);

void f1(func); // ok: f1 has a parameter of function type

func f2(int);  // error: f2 has a return type of function type

func *f3(int); // ok: f3 returns a pointer to function type

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值