#《Essential C++》讀書筆記# 第二章 面向過程的編程風格

基礎知識

函數必須先被聲明,而後才能被調用(被使用)。函數的聲明讓編譯器得以檢查後續出現的使用方式是否正確——是否有足夠的參數、參數類型是否正確,等等。函數聲明沒必要提供函數體,但必須指明返回類型、函數名,以及參數列表。此即所謂的函數原型(function prototype)。ios

若是函數的返回類型不爲void,那麼它必須在每一個可能退出點上將值返回。函數中的每條return語句都被用來明確表示該處就是函數的退出點。若是函數體最後一條語句不是return,那麼最後一條語句以後即是該函數的隱式退出點。 程序員

當咱們以by reference方式將對象做爲函數參數傳入時,對象自己不會複製出另外一份——複製的是對象的地址。函數中對該對象進行的任何操做,都相對因而對傳入的對象進行間接操做。將參數聲明爲reference的理由之一是,但願得以直接對所傳入的對象進行修改;第二個理由是,下降複製大型對象的額外負擔。數組

咱們也可使用pointer形式傳遞函數參數,這和以reference傳遞的效果相同:傳遞的是對象的地址,而不是整個對象的副本。可是二者用法不一樣。pointer參數和reference參數之間更重要的差別是,pointer可能(也可能不)指向某個實際對象。當咱們提領pointer時,必定要先肯定其值並不是0。至於reference,則一定會表明某個對象,因此不須要作此檢查。ide

但使用delete釋放heap(堆,動態內存)分配而來的對象是,無需檢驗指針爲零,編譯器會自動進行這項檢查。若是由於某種緣由,程序員不想使用delete表達式,由heap分配而來的對象就永遠不會被釋放,這稱之爲memory leak(內存泄漏)。函數

在選擇函數參數使用pointer仍是reference時,咱們要知道,pointer能夠被設置爲0,表示未指向任何一個對象,而reference必定得表明某個對象,沒法被設置爲0。性能

將函數聲明爲inline,表示要求編譯器在每一個函數調用點上,將函數的內容展開。面對一個inline函數,編譯器可將該函數的調用操做改成以一份函數代碼副本代替,這將使咱們得到性能改善。將函數指定爲inline,只是對編譯器提出的一種要求,而沒有強制性,編譯器是否執行這項請求,需視編譯器狀況而定。測試

函數重載機制(function overloading),參數列表不相同(多是參數類型不一樣,多是參數個數不一樣)的兩個或多個函數,能夠擁有相同的函數名稱。編譯器會將調用者提供的實際參數拿來和每一個重載函數的參數對比,找出其中最合適的。編譯器沒法根據函數返回類型來區分兩個具備相同名稱的函數,由於返回類型沒法保證提供給咱們一個足以區分不一樣重載函數的語境。spa

函數的定義只能有一份,能夠有許多份聲明。咱們不把函數的定義放入頭文件,由於同一個程序的多個代碼文件可能都會包含這個頭文件。「只定義一份」的規則例外:inline函數的定義,爲了能擴展inline函數的內容,在每一個調用點上,編譯器都取得其定義,這意味着咱們必須將inline函數的定義放在頭文件,而不是把它放在各個不一樣的程序代碼文件中;const object和inline函數同樣,是「只定義一份」規則下的例外,const object的定義只要一出文件以外便不可見,這意味着咱們能夠在多個程序代碼文件中加以定義,不會致使任何錯誤。(注意指向const object 的指針,其自己可能並非const object)prototype

在引用頭文件時,若是頭文件和包含此程序代碼文件位於同一個磁盤目錄下,咱們便使用雙引號,若是在不一樣的磁盤目錄下,咱們便使用尖括號。更有技術含量的回答是,若是此文件被認定爲標準的或項目專屬的頭文件,咱們便以尖括號將文件名括住,編譯器搜索此文件時,會先在某些默認的磁盤目錄中尋找;若是文件名由成對的雙引號括住,此文件便被認爲是一個用戶提供的頭文件,搜索此文件時,會由包含此文件的文件所在磁盤目錄開始找起。指針

練習題答案

練習2.1 先前的main()只讓用戶輸入一個位置值,而後便結束程序。若是用戶想取得兩個甚至更多元素值,它必須執行這個程序兩次或屢次。請改寫main(),使它容許用戶不斷輸入位置值,直到用戶但願中止爲止。

fibon_elem.h
bool fibon_elem(int pos, int& elem)
{
    if (pos <= 0 || pos > 45)
    {
        elem = 0;
        return false;
    }
    elem = 1;
    int n_2 = 1, n_1 = 1;
    for (int ix = 3;ix <= pos;++ix)
    {
        elem = n_2 + n_1;
        n_2 = n_1;
        n_1 = elem;
    }
    return true;
}



#include <iostream>
#include "fibon_elem.h"

using namespace std;

extern bool fibon_elem(int, int&);

int main()
{
    int pos, elem;
    char ch;
    bool more = true;
    while (more)
    {
        cout << "Please enter a position: ";
        cin >> pos;
        if (fibon_elem(pos, elem))
        {
            cout << "element # " << pos
                << " is " << elem << endl;
        }
        else
        {
            cout << "Sorry. Counld not calculate element # "
                << pos << endl;
        }
        cout << "would you like to try again? (y/n) ";
        cin >> ch;
        if (ch != 'y'  && ch != 'Y')
        {
            more = false;
        }
    }
    return 0;
}

練習2.2 Pentagonal數列的求值公式是P(n)=n(3n-1)/2,藉此產生1,5,12,22,35等元素值。試定義一個函數,利用上述公式,將產生的元素放到用戶傳入的vector之中,元素個數由用戶指定。請檢查元素個數的有效性(太大可能引起overflow問題)。接下來編寫第二個函數,可以將給定的vector的全部元素一一打印出來。此函數的第二參數接受一個字符串,表示存放在vector內的數列的類型。最後再寫一個main(),測試上述兩個函數。

#include <iostream>
#include <vector>
#include <string>

using namespace std;

bool calc_elements(vector<int>& vec, int pos);
void display_elems(vector<int>& vec, const string& title, ostream& os = cout);

int main()
{
    vector<int> pent;
    int pos;
    const string title("Pentagonal Numeric Series");
    cout << "Please enter a position: ";
    cin >> pos;
    if (calc_elements(pent, pos))
    {
        display_elems(pent, title);
    }
    return 0;
}

bool calc_elements(vector<int>& vec, int pos)
{
    if (pos <= 0 || pos > 100)
    {
        cerr << "Sorry. Invaild position: " << pos << endl;
        return false;
    }
    for (int ix = vec.size() + 1;ix <= pos;++ix)
    {
        vec.push_back(ix * (3 * ix - 1) / 2);
    }
    return true;
}

void display_elems(vector<int>& vec, const string& title, ostream& os)
{
    os << '\n' << title << "\n";
    for (int ix = 0;ix < vec.size();++ix)
    {
        os << vec[ix] << '\t';
        if ((ix + 1) % 10 == 0)
        {
            cout << endl;
        }
    }
    os << endl;
}

練習2.3 將練習2.2的Pentagonal數列求值函數拆分爲兩個函數,其中之一爲inline,用來檢驗元素個數是否合理。若是的確合理,並且還沒有被計算,便執行第二個函數,執行實際的求值工做。

#include <iostream>
#include <vector>
#include <string>

using namespace std;

void really_calc_elems(vector<int>& , int );
inline bool calc_elems(vector<int>&, int);
void display_elems(vector<int>& vec, const string& title, int, ostream& os = cout);

int main()
{
    vector<int> pent;
    int pos;
    char ch;
    bool more = true;
    const string title("Pentagonal Numeric Series");
    while (more)
    {
        cout << "Please enter a position: ";
        cin >> pos;
        if (calc_elems(pent, pos))
        {
            display_elems(pent, title, pos);
        }
        cout << "would you like to try again? (y/n) ";
        cin >> ch;
        if (ch != 'y' && ch != 'Y')
        {
            more = false;
        }
    }
    return 0;
}

inline bool calc_elems(vector<int>& vec, int pos)
{
    if (pos <= 0 || pos > 100)
    {
        cerr << "Sorry. Invalid position: " << pos << endl;
        return false;
    }
    if (vec.size() < pos)
    {
        really_calc_elems(vec, pos);
    }
    return true;
}

void really_calc_elems(vector<int>& vec, int pos)        
{
    for (int ix = vec.size() + 1;ix <= pos;++ix)
    {
        vec.push_back((ix * (3 * ix - 1) / 2));
    }
}

void display_elems(vector<int>& vec, const string& title, int pos, ostream& os)
{
    os << '\n' << title << "\n";
    for (int ix = 0;ix < pos;++ix)
    {
        os << vec[ix] << '\t';
        if ((ix + 1) % 10 == 0)
        {
            cout << endl;
        }
    }
    os << endl;
}

練習2.4 寫一個函數,以局部靜態(local static)的vector儲存Pentagonal數列元素。此函數返回一個const指針,指向該vector。若是vector的大小小於指定的元素個數,就擴充vector的大小。接下來再實現第二個函數,接受一個位置值,返回該位置上的元素。最後,編寫main()測試這些函數。

#include <iostream>
#include <vector>

using namespace std;

inline bool check_validity(int pos);
const vector<int>* pentagonal_series(int pos);
bool pentagonal_elem(int pos, int& elem);

int main()
{
    int pos, elem;
    char ch;
    bool more = true;
    while (more)
    {
        cout << "Please enter a position: ";
        cin >> pos;
        if (pentagonal_elem(pos, elem))
        {
            cout << "element " << pos << " is " << elem << endl;
        }
        cout << "would you like to continue? (y/n) ";
        cin >> ch;
        if (ch != 'y' && ch != 'Y')
        {
            more = false;
        }
    }
    return 0;
}

inline bool check_validity(int pos)
{
    return (pos <= 0 || pos > 100) ? false : true;
}

const vector<int>* pentagonal_series(int pos)
{
    static vector<int> _elems;
    if (check_validity(pos) && (pos > _elems.size()))
    {
        for (int ix = _elems.size() + 1;ix <= pos;++ix)
        {
            _elems.push_back((ix * (3 * ix - 1)) / 2);
        }
    }
    return &_elems;
}

bool pentagonal_elem(int pos, int& elem)
{
    if (!check_validity(pos))
    {
        cout << "Sorry. Invalid position: " << pos << endl;
        elem = 0;
        return false;
    }
    const vector<int>* pent = pentagonal_series(pos);
    elem = (*pent)[pos - 1];
    return true;
}

練習2.5 實現一個重載的max()函數,讓它接受如下參數:(a)兩個整數,(b)兩個浮點數,(c)兩個字符串,(d)一個整數vector,(e)一個浮點數vector,(f)一個字符串vector,(g)一個整數組,以及一個表示數組大小的整數值,(h)一個浮點數組,以及一個表示數組大小的整數值,(i)一個字符串數組,以及一個表示數組大小的整數值。最後,編寫main()測試這些函數。

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

inline int max(int t1, int t2)
{
    return t1 > t2 ? t1 : t2;
}

inline float max(float t1, float t2)
{
    return t1 > t2 ? t1 : t2;
}

inline string max(string t1, string t2)
{
    return t1 > t2 ? t1 : t2;
}

inline int max(const vector<int>& vec)
{
    return *max_element(vec.cbegin(), vec.cend());
}

inline float max(const vector<float>& vec)
{
    return *max_element(vec.cbegin(), vec.cend());
}

inline string max(const vector<string>& vec)
{
    return *max_element(vec.cbegin(), vec.cend());
}

inline int max(const int* parray, int size)
{
    return *max_element(parray, parray + size);
}

inline float max(const float* parray, int size)
{
    return *max_element(parray, parray + size);
}

inline string max(const string* parray, int size)
{
    return *max_element(parray, parray + size);
}

int main()
{
    int size = 5;
    int n = 1, n2 = 9;
    float f = 0.34, f2 = 9.3;
    string s = "dfsdg", s2 = "dafsdfsad";
    vector<int> ivec = { 12,70,2,169,1,5,29 };
    vector<float> fvec = { 2.5,24.8,18.7,4.1,23.9 };
    vector<string> svec = { "we","were","her","pride","of","ten" };
    int iarray[5] = { 1,2,3,4,5 };
    float farray[5] = { 5.0,4.0,3.0,2.0,1.0 };
    string sarray[5] = { "a","b","c","asfs","aaa" };
    cout << "max(n,n2)=" << max(n, n2) << "\n"
        << "max(f,f2)=" << max(f, f2) << "\n"
        << "max(s,s2)=" << max(s, s2) << "\n"
        << "max(ivec)=" << max(ivec) << "\n"
        << "max(fvec)=" << max(fvec) << "\n"
        << "max(svec)=" << max(svec) << "\n"
        << "max(iarray,size)=" << max(iarray, size) << "\n"
        << "max(farray,size)=" << max(farray, size) << "\n"
        << "max(sarray,size)=" << max(sarray, size) << "\n";
    return 0;
}

練習2.6 以template從新完成練習2.5,並對main()函數作適當的修改。

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

template <typename Type>
inline Type new_max(Type t1, Type t2)
{
    return t1 > t2 ? t1 : t2;
}

template <typename elemType>
inline elemType new_max(const vector<elemType>& vec)
{
    return *max_element(vec.cbegin(), vec.cend());
}

template <typename arrayType>
inline arrayType new_max(const arrayType* parray, int size)
{
    return *max_element(parray, parray + size);
}


int main()
{
    int size = 5;
    int n = 1, n2 = 9;
    float f = 0.34, f2 = 9.3;
    string s = "dfsdg", s2 = "dafsdfsad";
    vector<int> ivec = { 12,70,2,169,1,5,29 };
    vector<float> fvec = { 2.5,24.8,18.7,4.1,23.9 };
    vector<string> svec = { "we","were","her","pride","of","ten" };
    int iarray[5] = { 1,2,3,4,5 };
    float farray[5] = { 5.0,4.0,3.0,2.0,1.0 };
    string sarray[5] = { "a","b","c","asfs","aaa" };
    cout << "max(n,n2)=" << new_max(n, n2) << "\n"
        << "max(f,f2)=" << new_max(f, f2) << "\n"
        << "max(s,s2)=" << new_max(s, s2) << "\n"
        << "max(ivec)=" << new_max(ivec) << "\n"
        << "max(fvec)=" << new_max(fvec) << "\n"
        << "max(svec)=" << new_max(svec) << "\n"
        << "max(iarray,size)=" << new_max(iarray, size) << "\n"
        << "max(farray,size)=" << new_max(farray, size) << "\n"
        << "max(sarray,size)=" << new_max(sarray, size) << "\n";
    return 0;
}

end。

「紙上得來終覺淺,絕知此事要躬行。」

相關文章
相關標籤/搜索