欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

c++ primer 7 函数

程序员文章站 2022-03-02 13:54:43
...
7.2参数传递
    7.2.1非引用形参
    普通的非引用类型的参数通过复制对应的实参实现初始化。
    当用实参副本初始化形参时,函数并没有访问调用所传递的实参本身,因此不会修改实参的值。
 
    1指针形参
    函数的形参可以是指针,此时将复制实参指针。与其他非引用类型的形参一样,该类形参的任何改变也仅作用于局部副本。
    如果函数将新指针赋给形参,主调函数使用的实参指针的值没有改变。
 
    事实上被复制的指针只影响对指针的赋值,如果函数形参是非const类型的指针,则函数可通过指针实现赋值,修改指针所指向对象的值
    
#include <iostream>
 
using namespace std;
 
void reset(int *p)
{
//*p = 1;
p = 0;
}
 
int main(void)
{
int a = 10;
reset(&a);
cout << a <<endl;
}
 

    

    2 const形参
    在调用函数时,如果该函数使用非引用的非const形参,则既可给该函数传递const实参也可传递非const的实参。
        
    3复制实参的局限性
    当需要在函数中修改实参的值时
    当需要以大型对象作为实参传递时
    当没有办法实现对象的复制时。
 
    
  
    7.2.2引用形参
    形参定义为引用类型
   void swap(int &v1,int &v2)
    {
    }
 
    引用形参直接关联到其所绑定的对象,而并非这些对象的副本。
    定义引用时,必须用与该引用绑定的对象初始化该引用。引用形参完全以相同的方式工作。
    每次调用函数,引用形参被创建并与相应实参关联。
 
    1 使用引用形参返回额外的信息
    vector<int>::const_iterator find_val(vector<int>::size_type &ocurs) {}
 
    2 利用const引用避免复制
    
    3 更灵活的指向const的引用
    
 

7.2.3 Vector和其他容器类型的形参
    通常,函数不应该有vector或其他标准库容器类型的形参。调用含有普通的非引用vector形参的函数将会复制vector的每一个元素
 
    从避免复制vector的角度出发,应考虑将形参声明为引用类型
 

7.2.4 数组形参
    数组有二个特殊性质,影响我们定义和使用在数据上的函数:一是不能复制数组,二是使用数组名字时,数组名会自动转化为指向其第一个元素的指针
    1 数组形参的定义
    
#include <iostream>
#include <string>
 
using namespace std;
 
void printValue1(int*)
{
 
}
 
void printValue2(int[])
{
 
}
 
void printValue3(int[10])
{
 
}
 
int main(void)
{
int *arr = {1,2,3,4,5};
printValue1(arr);
}
 
    2 形参的长度会引起误解
    3 数组实参
    数组形参可以定义为引用或非引用类型。大部分情况下,数组以普通的非引用类型传递。而在传递数组时,实参是指向数组第一个元素的指针,形参复制的是这个指针的值,而不是数组元素本身。
 
    4 通过引用传递数组
    数组形参可声明为数组的引用。如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。    
 

7.2.5 传递给函数的数组的处理
    第一种方法:在数据本身放置一个标记来检测数组的结束。C风格字符串就是采用这种方法,它是一种字符数组,并且以空字符null作为结束的标记。
    1 使用标准库规范
    传递指向数组第一个和最后一个元素的下一个位置的指针
    
#include <iostream>
#include <string>
 
using namespace std;
 
void printValues(const int *beg,const int *end)
{
while(beg != end)
{
cout << *beg++ <<endl;
}
}
 
int main(void)
{
int arr[2] = {1,2};
printValues(arr,arr+2);
return 0;
}
 
    2 显式传递表式数组大小的形式
    
#include <iostream>
#include <string>
 
using namespace std;
 
void printValues(const int ia[],size_t size)
{
for(int i=0; i != size;++i)
{
cout << ia[i] <<endl;
}
}
 
int main(void)
{
int arr[2] = {1,2};
printValues(arr,sizeof(arr) / sizeof(*arr));
return 0;
}
 
    7.2.6 main处理命令行选项
    
 
7.3 return语句
    7.3.1 没有返回值的函数
    在返回类型为void的函数中,return返回语句不是必须的,隐式的return 发生在函数的最后一个语句完成时。
 
    7.3.2 具有返回值的函数
    1 主函数main的返回值
    允许主函数main没有返回值就可结束。如果程序控制执行到主函数main的最后一个语句还没有返回,那么编译器会隐式地插入返回0的语句。
    
    2 返回非引用类型
    函数的返回值用于初始化在调用函数处创建的临时对象。
    
    3 返回引用
    当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。
const &shortString(const string &s1,const string &s2)
{
 
}
 
    4 千万不要返回局部对象的引用
    
    5 引用返回左值
    
    6 千万不要返回指向局部对象的指针
 

7.4 函数声明
 
   1  默认实参
    默认实参是通过给形参表中的形参提供明确的初始值来指定的。
    程序员可以为一个或多个形参定义默认值。但是,如果有一个形参具有默认实参,那么,它后面所有形参都必须有默认实参。
    
string screenInit(string::size_type height=24,string::size_type weight = 90 )
{
cout << height <<endl;
cout << weight <<endl;
return "success";
}
    
    2 指定默认实参的约束
    即可以在函数声明也可以在函数定义中指定默认实参。但是,在一个文件中,只能为一个形参指定默认实参一次。
    
 
 

7.5 局部对象
    7.5.1自动对象
    只有当定义它的函数被调用时才存在的对象称为自动对象。自动对象在每次调用函数时创建和撤销。
    
    7.5.2静态局部对象
    static局部对象,确保不迟于在程序执行流程第一次经过该对象的定义语句时进行初始化。这种对象一旦被创建,在程序结束前不会被撤销
 
    

7.6 内联函数
    1 内联函数避免函数调用的开销
    将函数指定为内联函数,就是将它在程序中的每个调用点上 内联地 展开。
    inline const string &shortString(const string &s1,const string &s2){}
 
    2 把内联函数放入头文件
    在头文件中加入或修改内联函数时,使用了该头文件的所有源文件都必须重新编译。
 
    

7.7 类的成员函数
    
 
#include <iostream>
 
using namespace std;
 
class Sale {
public:
double avg_price() {
cout << "avg_price" <<endl;
return 100;
}
 
private:
string isbn;
double age;
};
 
int main()
{
Sale sale;
sale.avg_price();
return 0;
}
    
 
7.7.1 定义成员函数的函数体
    1 成员函数含有额外的、隐含的形参
    调用成员函数,实际上是使用对象来调用的。
 
    2 this指针的引入
    每个成员函数都有一个额外的、隐含的形参this。在调用成员函数时,形参this初始化为调用函数的对象的地址。
    在调用成员函数时,形参this初始化为调用函数的对象的地址。
 
    3 const成员函数的引入
    由于this是指向const对象的指针,const成员函数不能修改调用该函数的对象。
    const对象、指向const对象的指针或引用只能用于调用const成员函数,如果尝试用它们来调用非const成员函数,则是错误的。
    
    4 this指针的使用
    在成员函数中,不必显式的使用this指针来访问被调用函数所属对象的成员。对这个类的成员的任何没有前缀的引用,都被假定为通过指针this实现的引用。
 
 
7.7.2 在类外定义成员函数
    1 构造函数是特殊的成员函数
    2 构造函数的定义
    3 构造函数的初始化列表
    4 合成的默认构造函数
 
class Sale {
public:
Sale():age(10)
{
cout << age<< endl;
}
double avg_price() {
cout << "avg_price" <<endl;
return 100;
}
 
private:
string isbn;
double age;
};
    
7.7.4 类代码文件的组织
    通常将类的声明放置在头文件中。大多数情况下,在类外定义的成员函数则置于源文件中
 
 

7.8 重载函数
    出现在相同作用域中的二个函数,如果具有相同的名字而形参表不同,则称为重载函数
 
7.9 指向函数的指针
    函数指针是指指向函数而非指向对象的指针。
    
    bool (*pf) (const string &,const string &);
    语句将pf声明为指向函数的指针,它所指向的函数带有二个const string &类型的形参和bool类型的返回值
    *pf 二侧的圆括号是必须的
    
    1 用typedef简单函数指针定义
    typedef bool (*cmpFcn) (const string &,const string &);
    该定义表示cmpFcn是一种指向函数的指针类型的名字。
    该指针的类型为"指向返回bool类型并带有二个const string引用形参的函数的指针"
 
    2 指向函数的指针的初始化和赋值
    在引用函数名但又没有调用该函数时,函数名将被自动解释为指向函数的指针。
    
    3 通过指针调用函数
    指向函数的指针可用于调用它所指向的函数。可以不需要使用解引用操作符,直接通过指针调用函数。
    
#include <iostream>
#include <string>
 
using namespace std;
using std::string;
 
bool getLength(const string &a,const string &b)
{
cout << "function point" + a + " " + b <<endl;
return true;
}
 
int main(void)
{
typedef bool (*cmpFn) (const string &,const string &);
cmpFn fn = getLength;
fn("admin","root");
return 0;
}
    4 函数指针形参
    函数的形参可以是指向函数的指针。这种形参可以用以下二种形式编写。
    
void useBigger(const string &,const string &,bool(const string &,const string &));
void useBigger(const string &,const string &, bool (*)(const string &,const string &));