C++: Essential C++ 读书笔记(chapter2):面向过程编程:提供默认参数值

C++: Essential C++ 读书笔记:面向过程编程:提供默认参数值

案例:

在我们的冒泡排序程序中,为了将跟踪信息打印到 ofil,我必须希望加以调试的函数都能够使用 ofil。我选择的快速方案是让许多函数都可以看到这个对象:换句话说,我在 file scope中定义 ofil 是一个不明智的举动。

一般的程序编写法则是:以“参数传递”作为函数间的沟通方式,比“直接将对象定义在file scope”更适当,理由之一:函数如果过度依赖 file scope内对象,就比较难以在其他环境中重用,也比较难以修改----因为我们不仅要了解函数的工作逻辑,还要了解定义于 file scope中的那些对象的工作逻辑。 

那么,我们应该做怎样的修改,才能使它摆脱对 file scope内 ofil 的依赖。

void bubble_sort(vector<int> &vec, ofstream &ofil)
{

    for(int ix = 0; ix < vec.size(); ix++) {
        for (int jx = ix +1; jx < vec.size(); ++jx) {
            if (vec[ix] > vec[jx]) {
                ofil << "about to call swap! ix: " << ix
                     << "  jx: "<< jx 
                     << vec[ix] << " with "<< vec[jx] << endl;

                swap(vec[ix], vec[jx], ofil);
            }
        }
    }
}

虽然上述代码使我们摆脱了对 file scope 内 ofil 的依赖,但它同时也带来令人困惑的问题。现在,每次调用 bubble_sort()函数都必须传入一个 参数 ofstream 对象,而且用户无法关闭我们所产生的信息。通常,当一切都上了正轨,就没有人再会想看这些信息了。 

我们的预期是:用户不必指定输出用的stream,而且有能力将输出信息关闭,默认情况下我们不想产生这些信息,但是我们又希望让那些想看到这些信息的用户可以产生它们,甚至指定其输出文件,那么该如何是好了? 

C++允许我们为全部或者部分参数设置默认值 

所以我们可以将本例中的  ofstream 指针参数默认值设置为0

void bubble_sort(vector<int> &vec, ofstream *ofil = 0)
{

    for(int ix = 0; ix < vec.size(); ix++) {
        for (int jx = ix +1; jx < vec.size(); ++jx) {
            if (vec[ix] > vec[jx]) {
                ofil << "about to call swap! ix: " << ix
                     << "  jx: "<< jx 
                     << vec[ix] << " with "<< vec[jx] << endl;

                swap(vec[ix], vec[jx], ofil);
            }
        }
    }
}

注意:我们将 bubble_sort() 函数中的第二个形参,声明为 ofstream对象的一个 pointer指针 而非 reference。

我们必须 做这样的改变,才可以为它设定默认值 0,并且未指向任何ofstream 对象 。

reference不同于 poiner,reference无法被设置为0。因此,reference一定得代表某个对象。

于是,有了这样的改变后,当用户以单一参数调用: bubble_sort()时,不会产生任何调试信息,如果调用时带有第二个参数,指向某个 ofstream对象,那么这个函数变会产生调试信息。 

int mian()
{

    int ia[8] = {8,32,3,13,1,21,5,2};
    vector<int> vec(ia, ia+8);

    // 以下就像调用 bubble_sort(vec, 0) 一样,不会产生任何调试信息
    bubble_sort(vec);
    display(vec);

    // 以下调用会产生:调试信息
    ofstream ofil ("data.txt");
    bubble_sort(vec, &ofil);
    display(vec, ofil);
}

其实,display()的实现呈现出另外一种情况,到目前为止,display()仍然将输出写死到 cout身上。一般情况下输出至 cout当然很好,但是有时候用户可能会希望提供一个不同的目的地,例如:文件。,所以,我们必须能够在 main()之中同时支持这两种方式。

那么,  解决方案就是:让 cout 成为默认的 ostream参数 

void  display(const vector<int> &vec, ostream &os = cout)
{

    for(int ix = 0; ix < vec.size(); ix++)
    {

        os << vec[ix] << ' ';
    }
    os <<endl;
}

提供参数默认值 规则

规则一:默认值得解析(resolve)操作由最右边开始进行,如果我们为某个参数提供了默认值,那么这一参数右边的所有参数都必须也具有默认参数值才行。

// 非法: 没有为 vec 提供默认值

void display(ostream &os = cout , const vector<int> vec)  

规则二:默认值只能指定一次,可以在函数声明处,也可以在函数定义处,但是不能在两个地方都指定。那么,我们应该在何处指定参数的默认值了 ?

通常:

  1. 函数声明会被放在头文件中,每个打算使用该函数的文件,都会将头文件包含进来,
  2. 函数的定义通常放在程序代码中,该文件只被编译一次,当我们想要使用该函数时,会将它链接 link 到我们的程序中来。也就是说头文件带来更高的可见性。

猜你喜欢

转载自blog.csdn.net/u013620306/article/details/128596136