const 形参:
如果将函数形参定义为非引用的const类型,EX: void fcn(const int i) {}; 则不能修改实参的局部副本。
注意: void fcn(const int i) {}; 和 void fcn(int i) {}; 编译的结果是一样的。
规则: 如果使用引用实参的
唯一目的是避免复制实参,则应该将实参定义为
const 引用
EX: bool isShorter(const string &s1, const string &s2) ;
注意: 非const引用实参 只能与完全同类型的非const对象关联
应该将不修改相应实参的形参定义为const 应用。 这样就不会限制函数的应用,因为和形参相关的类型都可以作为实参传递,比如 void func( const string &s) ; 可以这样调用 func("hello word");
普通的非const引用形参在使用是不太灵活。这样的形参既不能用const对象初始化,也不能用字面值或产生右值的表达式实参初始化。
指向指针的引用:
EX: int *&v1; 从右往左理解: v1 是一个引用, 与指向int型对象的指针相关联。
补充:以下两个问题不是很明白,求路过的各位爷指点指点。
问题: 什么时候不应该将形参定义为引用???
问题: 什么时候应使用指针形参?什么时候应使用引用形参?两者的优缺点?
摘自『高质量c++编程』条款一:指针与引用的区别指针与引用看上去完全不同(指针用操作符’*’和’->’,引用使用操作符’.’),但是它们似乎有相同的功能。指针与引用都是让你间接引用其他对象。你如何决定在什么时候使用指针,在什么时候使用引用呢?首先,要认识到在任何情况下都不能用指向空值的引用。一个引用必须总是指向某些对象。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。
不需要修改数组形参的元素是,函数应该将形参定义为指向const对象的指针: void f(const int*);{/*.....*/}
通过引用传递数组: 如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组 的引用本身。这时,数组大小成为形参和实参类型的一部分,编译器会检查实参的大小与形参的大小是否匹配。
EX: void printValue(int (&arr)[10]) {/*...*/};
多维数组的传递:
多维数组以指向0号元素的指针方式传递,多维数组的元素本身就是数组,除了第一维以外的所有维的长度都是元素的一部分,必须明确指定。
EX : void printValue(int (*matirx)[10], int rowSize); // matrix 声明为指向含有10个 int型元素的数组的指针。
再次辨析:
int &arr[10]; // [] 优先级高于$ ;定义了arr 这个数组,数组长度为10,数组元素为int 型的引用。
int (&arr) [10]; // 定义了 arr这个引用,引用的类型是 int[10]; 即 arr 是 长度为10的数组的引用。
int *matrix[10]; // 长度为10 ,元素为int*指向int的指针 的数组,解析如上。
int (*matirx)[10]; // 定义了指向 (长度为10,元素是整型的数组)的指针
函数的返回值:
1) 返回非引用类型; 注意: 函数的返回值用于初始化在调用函数处创建的临时对象。
2) 返回引用; 注意: 当函数返回引用类型是,没有复制返回值。
EX: // find shorter of two strings
const string
&shorterString(const string &s1, const string &s2)
{ return s1.size()<s2.size()? s1:s2; }
注: 调用函数和返回结果时,都没有复制这些string 对象。
3)不要返回局部对象的引用。
指定默认实参的约束: 在一个文件中,只能为一个形参指定默认实参一次。
通常,应在函数声明中指定默认实参,并将该声明放在合适的头文件中。
局部对象:
1)自动对象:默认情况下,局部变量的生命期局限于所在函数的每次执行期间。只有当定义它的函数被调用时才存在的对象称为自动对象。自动对象在每次调用函数时创建和撤消。 形参也是自动对象
2)静态局部对象:static , static 局部对象确保不迟于在程序执行流程第一次经过该对象的定义语句时进行初始化,这种对象一旦创建,在程序结束前都不会被撤消。
内联函数:
1 内联数就是将它在程序的每个调用点上“内联地”展开。从而避免函数调用的开销。
2 关键字 inline
3 放置的位置: 头文件中
内联函数应该在头文件中定义。
回顾: 见笔记“第二章7/14 --C++ primer” 头文件例外的三种定义1、类的定义;2、const 对象 ;3 、inline 函数
原因: 内联函数的定义对编译器而言必须是可见,才能在调用点“内敛地”展开。
注意: 头文件加入或修改了内联函数时,使用了该头文件的所有源文件都必须重新编译。
类的成员函数:
1) 函数原型必须在类中定义。 函数体可以在类中或在类外定义
2) 编译器隐式地将在类中定义的成员函数当做内联函数
3)const 成员函数: EX : double avg_price() const {/*...*/}
类的成员函数都有一个隐含的形参 this, this 为调用函数的对象的地址。
const 改变了隐含的this 形参的类型,调用const 成员函数时, this形参将是一个指向 其对象的 const 类名* 类型的指针。 这种函数为常量成员函数。 const 成员函数不能修改调用该函数的对象。
注: const 对象、指向const 对象的指针或引用只能用于调用其const 成员函数。
函数的重载:
形参是否为const 是否可以区分两个函数:
EX: void lookup(phone);
void lookup(const phone);
以上两个生命属于重复声明。
原因: 实参传递的方式,复制形参时并不考虑形参是否为const, 函数操作的只是副本,函数无法修改实参。所以既可将const 对象传递给const形参,也可传递给非const 形参。 这两种形参无本质差别。
注意:形参与const 形参的等价性仅适用于非引用形参。
有const 引用形参的函数 和 有非const 引用形参的函数是不同的。类似的,带有指向const 类型的指针形参和 带有指向相同类型的非const 对象的指针形参的函数是不同的。
结论: 仅当形参是引用或指针时,形参是否为const 才有影响。
注意: 不能基于指针本身是否为const 来实现重载
f(int *);
f(int *cont); // error
指向函数的指针: 函数指针也指向某个特定的类型。函数类型有其返回类型以及形参表确定。
EX: bool (*pf) (const string& ,const stirng &);
使用typedef 简化定义:
EX: typedef bool (*cmpFcn) (const string& ,const stirng &);
cmpFcn pf ;
函数指针的初始化和赋值: 同类型的函数或函数指针或0值常量表达式。 直接用函数名即可。
函数指针可以直接调用函数: pf("hi","hello");
返回指向函数的指针:
解析: int (*ff(int)) (int*,int);
从声明的名字开始由里而外理解。
ff(int) ff 声明一个函数,带有一个int的形参,函数返回 int (*) (int*, int) , 他是指向一个函数的指针,所指向的函数返回int 型并带有两个分别是 int* 和 int 型 的形参。
使用typedef 定义:
typedef int (*pf) (int *, int);
pf ff(int);