• C++是一个语言联邦(Federation of languages)

1. C Style language

2. Object-Oriented C++

3. Template C++

4. STL/TR1/boost..

 

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

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

  比如全局常量:

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

  在类中,类专属常量:

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

 

2. enum hack!

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对象。

posted on 2017-10-20 16:12  LevisonChen  阅读(218)  评论(0编辑  收藏  举报