Effective C++我爱编程

【Effective C++(1)】让自己习惯C++

2017-12-22  本文已影响19人  downdemo

01 视C++为一个语言联邦

02 尽量以const,enum,inline替换#define

#define ASPECT_RATIO 1.653
const double Aspectratio = 1.653; // 大写名称通常用于宏,这里改写法
const char* const authorName = “Scott”;
const std::string authorName("Scott");
class Gameplayer {
private:
    static const int NumTurns = 5; // 常量声明式
    int scores[NumTurns]; // 使用此常量
    ...
};
// 上述是声明式而非定义式,如果编译器要看到一个定义式,这样写
const int Gameplayer::NumTurns; // 不用赋值,因为声明时已经有了初值

// 如果编译器较老不允许static成员在声明式上获得初值,可以将初值放在定义式
class CostEstimate {
private:
    static const double FudgeFactor; // 常量声明位于头文件内
    ```
};
const double CostEstima::FudgeFactor = 1.35; // 位于实现文件内
class GamePlayer {
private:
    enum { NumTurns = 5; }
    int scores[NumTurns];
    ...
};
// 对a和b的较大值调用f
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
int a = 5, b = 0;
CALL_WITH_MAX(++a, b); // a累加2次
CALL_WITH_MAX(++a, b + 10); // a累加1次
template <typename T>
inline void callWithMax(const T& a, const T& b)
{
    f(a > b ? a : b);
}

03 尽可能使用const

void f1(const Widget* pw);
void f2(Widget const* pw);
std::vector<int> v{1, 2};
const std::vector<int>::iterator it = v.begin();
*it = 10; // 正确
++it; // 错误
std::vector<int>::const_iterator it2 = v.begin(); // 相当于v.begin()
*it2 = 10; // 错误
++it2; // 正确
class Rational { ... };
const Rational operator*(const Rational& lhs, const Rational& rhs);
// 为什么要用const,往下看
Rational a, b, c;
...
(a*b) = c;
// 在a * b的结果上再赋值,虽然是很明显的错但很容易无意识造成,例如
// if(a * b = c)
class CTextBlock {
public:
    ...
    std::size_t length() const;
private:
    char* pText;
    mutable std::size_t textLength;
    mutable bool LengthIsValid;
};
std::size_t CTextBlock::length() const
{
    if (!lengthIsValid) {
        textLength = std::strlen(pText);
        lengthValid = true;
    }
    return textLength;
}
// 注意形参类型是指针或引用,const才构成重载
const string& shorterString(const string& s1, const string& s2)
{
    return s1.size() <= s2.size() ? s1 : s2; // return的是常量
    // 注意,不要返回局部对象的引用或指针!
}
string& shorterString(string &s1, string &s2)
{
    auto& r = shorterString(const_cast<const string&>(s1),
                            const_cast<const string&>(s2));
    return const_cast<string&>(r); 
}
shorterString(s1, s2);
// 如果s1或s2中至少有一个常量,则只调用第一个函数
// 如果都是非常量则调用第二个,第二个再调用第一个
// 先把非常量转为常量形参,再把返回的常量转为非常量

04 确定对象被使用前已被初始化

class A{
public:
    A(const std::string& s, const std::list<int> n);
private: 
    std::string name;
    std::list<int> number;
    int x;
};
A::A(const std::string& s, const std::list<int> l)
{
    name = s; // 这些都是赋值而非初始化
    number = n;
    x = 0;
}
A::A(const std::string& s, const std::list<int> l)
   :name(s),
    number(n),
    x(0)
{}
A::A()
   :name(),
    number(),
    x(0)
{}
class Singleton {
public:
    static Singleton& Instance()
    {
        static Singleton instance;
        return instance;
    }
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
};
上一篇下一篇

猜你喜欢

热点阅读