Tekkaman

导航

 

Effective C++

1、只有int型的class static变量能在类中定义,其它类型(如double)只能在类中声明,在类外定义。

class Student {
private:
    // static int 可以在类中定义
    static const int age = 5;
};

class GamePlayer {
private:
    // 非int型static变量只能在类中声明
    static const double NumTurns;

    // 下面这行代码会有编译错误
    // static const double NumTurns = 1.35f;
};
// 在类外定义
const double GamePlayer::NumTurns = 1.35f;

2、能不用宏定义,就尽量不用。如下例,将宏替换为函数,就不会存在此问题。

#define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b))

void f(int value) {}

int main()
{
    int a = 5, b = 0;
    CALL_WITH_MAX(++a, b);    // a被累加2次
    CALL_WITH_MAX(++a, b+10); // a被累加1次

    getchar();
    return 0;
}

3、迭代器的作用就像个T*指针。const ::iterator 类似 T* const,而 ::const_iterator 类似const T*。

    std::vector<int> vec;

    const std::vector<int>::iterator iter = vec.begin(); // iter类似T* const
    *iter = 10; // 正确,iter指向的是非const
    //++iter; // 错误,iter本身是const

    std::vector<int>::const_iterator cIter = vec.begin(); // cIter类似 const T*
    //*cIter = 10; // 错误,cIter指向的内容是const
    ++cIter; // 正确,cIter本身是非const

4、operator类重载应当返回一个const变量。否则会产生如下问题。

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

int main()
{
    Rational a, b, c;
    // 因为返回值为const Rational,所以下行代码编译错误
    // (a*b) = c; 

    getchar();
    return 0;
}

  返回cosnt还可以避免,如下错误:

    if (a*b == c) {}

    // 下面属于手误,少打了一个=,会发生编译错误
    //if (a*b = c) {}

5、none-const operator[]应当返回一个none-const reference。否则,下述赋值代码就会失败。

  tb[0] = 'x'

6、const函数,必须返回一个const变量。否则会产生如下问题。

class CTextBlock {
public:
    CTextBlock(char*p)
    {
        pText = p;
    }
    char& operator[] (std::size_t position) const
    {
        return pText[position];
    }
private:
    char *pText;
};

int main()
{
    const CTextBlock cctb("Hello");
    char *pc = &cctb[0];
    *pc = 'J'; // 现在有了'Jello'这样的数据

    getchar();
    return 0;
}

 7、mutable在成员变量可以在const函数内被修改。

8、当const、non-const函数有相同逻辑代码时,用non-const函数调用const函数的实现。

char& operator[] (std::size_t position)
    {
        return const_cast<char&>(// 将cosnt属性移除
            static_cast<const CTextBlock>(*this)[position]
            );
    }

9、编译器会为类声明构造函数、析构函数、copy构造函数、copy assignment函数。

   如果声明了一个构造函数,编译器不再创建default构造函数。

class Empty {
public:
    Empty(){}
    Empty(const Empty& rhs){}
    ~Empty(){}
    Empty& operator=(const Empty& rhs){}
};

10、如果你打算在一个“内含reference成员”的class内支持赋值操作(assignment),你必须定义自己的copy assignment函数。此种情况下,编译器不会生为你生成copy assignment函数。

  内含const成员也是一样的,编译器拒绝生成copy assignment。

  如果基类copy assignment定义为private,则编译器也拒绝为derived class生成copy assignment。

11、把函数设置为private并不安全,因为member function、friend function还是可以访问private。

  将函数声明为priavte,而故意不实现它,现是解决方案。

  下在也是一种解决方案,但可能存在多重继承问题。

class Uncopyable{
protected:
    Uncopyable(){}
    ~Uncopyable(){}
private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator =(const Uncopyable&);
};

class Entry : private Uncopyable{};

12、每一个带有virtual函数的class都有一个vtable。

13、将拥有non-virtual析构函数的类作为基类是非常愚蠢的。

class SpecialString : public std::string // bad desing, string有个non-virtual destructor
{
public:
    SpecialString();
    ~SpecialString();

private:

};

  C++并没有你Java中的final class或C#中的sealed class机制。

14、析构函数绝对不要吐出异常。如果destructor调用的函数可能抛出异常,那么捕获它,吞下它。

15、不要在constructor、destructor中调用virtual函数。因为constructor、destructor中的virtual函数无效。

16、auto_ptr当copy、assignment时,内部指针会变为NULL。

        auto_ptr更好的方案是引用计数指针,shared_ptr。引用计数无法打破环状引用。

  auto_ptr、shared_ptr调用的都是delete,而非delete[]。如果需要delete[],可以用scoped_array、shared_array。

17、下述代码可能产生异常。

procesWidge(std::tr1::shared_ptr<Widget>(new Widget()), priority());

 

posted on 2017-11-26 21:45  Tekkaman  阅读(253)  评论(0编辑  收藏  举报