Eff C++ 筆記1

 • C++是一個語言聯邦(Federation of languages)函數

1. C Style languagethis

2. Object-Oriented C++spa

3. Template C++指針

4. STL/TR1/boost..代碼規範

 

 • 使用const,enum,inline代替#definecode

1.  使用const datatype constName = constValue 代替 #define constName constValue對象

  好比全局常量:blog

const int maxN = 1000005; //代替 #define maxN 1000005

  在類中,類專屬常量:編譯器

class someClass{
private:
    static const int maxN = 1000005;
    int someData[maxN];
    ...
}

 

2. enum hack!string

class someClass{
private:
    enum { maxN = 1000005 };//enum令maxN變成一個記號名稱
    int someData[maxN];
    ...
}

  enum的某些特性更像#define而不是const,某些狀況下更符合咱們的需求。(例如取地址對於enum不合法而對const就合法

  enum hack使template metaproprogramming的基礎技術。

 

3. 使用inline function代替宏

  常見宏 #define call_with_max(a, b) foo(a > b ? a : b) 會出現大量的錯誤,

必須使用小括號將參數所有區別 #define call_with_max(a, b) foo((a) > (b) ? (a) : (b)) ,

即使如此在實際操做時依舊容易出錯(不能擴展代碼與靈活調用),應用inline function取代

template <typename T>
inline void callWithMax(const T& a, const T& b){
    foo(a > b ? a : b);
}

 

 

 • Const的妙用

1. Const聲明幫助編譯器偵測出錯誤

  const指定了一個不可改動的對象,而編譯器會強制的實施它。(!指出來能夠得到編譯器的幫助,確保其不被違反!)

這個對象能夠是global或者namespace域中的常量。也能夠修飾block scope中被聲明爲static的對象,亦能夠修飾class內部的全部變量。

而對於指針,能夠指出指針自身指針所指二者皆是,或二者皆不是Const。在*左表示指針所指是常量,在*右表示指針自身是常量,而在*兩側表示二者皆是常量。

int someValue = 12345;
int* pSomeValue = someValue;        // 二者皆不是常量
const int* pSomeValue = someValue     // 所指爲常量
int* const pSomeValue = someValue     // 指針爲常量
const int* const pSomeValue = someValue // 二者皆是常量
void foo(const dataType* arg) // 傳入一個指向常量的指針
void foo(dataType const* arg) // 與上面相同 在*左次序顛倒沒有區別

迭代器也是指針衍生出來的,因此

std::vector<int> vec;
...
const std::vector<int>::iterator iter = vec.begin(); // 迭代器的做用就像一個 T* const (模板變量的常量指針)
*iter = 12345; // ok! 指針所指不是常量
++iter;     // error! 指針自己是常量

std::vector<int>::const_iterator cIter = vec.begin(); // cIter的做用如同一個 const T* (模板常量的變量指針)
*cIter = 12345; // error! 指針所指是常量
++cIter;     // ok! 指針自己不是常量

  

  將const應用於函數聲明

良定義的數據類型應儘可能避免隱式類型轉換,這時返回一個常量值就十分有用

class Rational {...};
const Rational operator+ (const Rational& lhs, const Rational rhs);
const Rational operator* (const Rational& lhs, const Rational rhs);
...

這樣定義, if(a * b = c) // 本意是想作一個if(a * b == c)的比較 這樣的錯誤就不會出現,而會被編譯器直接警告。

 

2. const成員函數

使用const來控制成員函數對對象的可讀寫性是很重要的,由於這樣可使class藉口更容易被理解,而且還可使操做const對象成爲可能。這對高效編寫代碼很重要。

class SomeText {
public:
    ...
    const char& operator[](std::size_t position) const
    { return text[position]; }
    char& operator[](std::size_t position)
    { return text[position]; }
}

SomeText text("Hello,world!");
std::cout << text[0]; // 調用non-const方法 能夠讀
text[0] = 'A';        // 調用non-const方法 能夠寫
const SomeText cText("Hello,world!");
std::cout << cText[0]; // 調用const方法 能夠讀
cText[0] = 'A';        // 調用const方法 不可寫!

對於在const中也想改變的量,使用mutable能夠聲明在const成員函數內依舊可被更改的變量。

若是成員函數代碼功能相同而只有常量變量的區別,能夠const_cast,static_cast來避免代碼重複。

class SomeText {
public:
    ...
    const char& operator[](std::size_t position) const
    {
        ...
        ...
        ...
        return text[position];
    }
    char& operator[](std::size_t position) {
        return const_cast<char&>         // 移除返回值的const
                (static_cast<const SomeText&> // 爲*this加上const
                    (*this)[position]);     // 調用const op[]
    }

 

 • 變量與對象的初始化與代碼規範

1. 代碼規範:

 類型  規範  示例
簡單數據類型  首字母小寫表示類型,以後按單詞分割每單詞首字母大寫。
int iMaxNum = 10000;
char cRank = 'A';
string sName = "LevisonChen";
double dSpeed = 1.357;
int* pMaxNum = iMaxNum;
複雜數據類型  首字母小寫,首詞表示數據類型,以後按單詞分割每單詞首字母大寫
std::vector<int> vecEdges;
函數 按單詞分割每單詞首字母大寫
void Foo(){ ... }
int GetMaxinum(std::vector<int> vecArg){ ... }
類與結構體 按單詞分割每單詞首字母大寫,私有字段不使用首詞表示數據類型
class SomeClass { ... }
struct SomeStruct { ... }
 縮進 tab-4spaces縮進 
{
    ...
    {
        ...
        {
            ...
            ...
            ...
        }
        ...
    }
    ...
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2. 不要混淆賦值(assignment)和初始化(initialization)

class Person {
public:
    Person(const std::string& sName,
           const std::int& iAge,
           const std::list<PhoneNumber>& listPhones,
           const std::list<EmailAddress>& listEmails);
private:
    std::string name;
    std::int age;
    std::list<PhoneNumber> phones;
    std::list<EmailAddress> emails;
};

Person::Person(const std::string& sName,
               const std::int& iAge,
               const std::list<PhoneNumber>& listPhones,
               const std::list<EmailAddress>& listEmails)
{
    name = sName;    
    age = iAge;
    phones = listPhones;
    emails = listEmails;
} // 這是賦值而非初始化!
Person::Person(const std::string& sName,
               const std::int& iAge,
               const std::list<PhoneNumber>& listPhones,
               const std::list<EmailAddress>& listEmails)
   :name(sName),    
    age(iAge),
    phones(listPhones),
    emails(listEmails)    // 這是初始化!
{} 

爲了消除跨編譯時的單元初始化次序問題,應以local static對象替換non-local static對象。

相關文章
相關標籤/搜索